### Launch Example App and Capture Screenshot Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/README.md Launch the example app on an iOS simulator with a specific tab and then capture a raw screenshot. This is used for generating iOS-simulator specific screenshots. ```bash xcrun simctl launch de.dmrschmidt.DSWaveformImageExample-iOS -tab 2 xcrun simctl io screenshot raw.png ``` -------------------------------- ### Minimal Configuration (Size Only) Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Configure the waveform with only the desired size. This is the most basic setup. ```swift Waveform.Configuration(size: CGSize(width: 500, height: 100)) ``` -------------------------------- ### Install DSWaveformImage via Swift Package Manager Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/README.md Add the DSWaveformImage package to your project using Swift Package Manager. This is the recommended installation method. ```bash https://github.com/dmrschmidt/DSWaveformImage (Up to Next Major from 14.0.0) ``` -------------------------------- ### Custom WaveformRenderer Example Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/Renderers.md Demonstrates how to create a custom renderer by conforming to the `WaveformRenderer` protocol and implementing the `path` and `render` methods. This custom renderer can then be used with `WaveformImageDrawer`. ```swift import DSWaveformImage struct MyCustomRenderer: WaveformRenderer { func path(samples: [Float], with configuration: Waveform.Configuration, lastOffset: Int, position: Waveform.Position) -> CGPath { let path = CGMutablePath() // Implement custom path logic return path } func render(samples: [Float], on context: CGContext, with configuration: Waveform.Configuration, lastOffset: Int, position: Waveform.Position) { // Implement custom rendering logic } } // Use: let myRenderer = MyCustomRenderer() let image = try await WaveformImageDrawer().waveformImage(fromAudioAt: url, with: config, renderer: myRenderer) ``` -------------------------------- ### CircularWaveformRenderer Example Usage Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/Renderers.md Demonstrates how to create instances of CircularWaveformRenderer for both circle and ring shapes. ```swift let circleRenderer = CircularWaveformRenderer(kind: .circle) let ringRenderer = CircularWaveformRenderer(kind: .ring(0.5)) ``` -------------------------------- ### ChannelAwareWaveformRenderer Example Implementation Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/Renderers.md Example of how to implement the ChannelAwareWaveformRenderer protocol, specifying a channel selection. Renderers that do not conform implicitly use .merged channel selection. ```swift struct MyRenderer: ChannelAwareWaveformRenderer { let channelSelection: Waveform.ChannelSelection = .specific(0) // left channel only // ... implement WaveformRenderer methods } ``` -------------------------------- ### Run WaveformScreenshots Executable Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/README.md Use this command to generate README images from the WaveformScreenshots SPM executable target. Ensure you have the Swift Package Manager installed and the executable is available. ```bash swift run WaveformScreenshots ``` -------------------------------- ### Initialize WaveformImageDrawer Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/WaveformImageDrawer.md Creates a stateless WaveformImageDrawer instance. This is the basic setup for using the drawer's rendering capabilities. ```swift let drawer = WaveformImageDrawer() ``` -------------------------------- ### Configuration Reference Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/README.md Complete reference for all configuration options available in DSWaveformImage, with illustrative examples for each setting. ```APIDOC ## Configuration ### Description Provides a comprehensive guide to all configurable options within the DSWaveformImage library. Each option is explained with examples demonstrating its effect on waveform rendering and analysis. ### Usage Use this reference to customize the behavior and appearance of waveform generation and display. ### Related Documentation - [Types](types.md) - [Errors](errors.md) ``` -------------------------------- ### Waveform Positioning Examples Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Demonstrates rendering waveforms at different vertical positions within the image. Use .top for alignment above content, .middle for centering, .bottom for alignment below content, or .custom(CGFloat) for a specific offset. ```swift let config = Waveform.Configuration(size: CGSize(width: 500, height: 100)) // Render at top let topWaveform = WaveformImageDrawer().waveformImage( fromAudioAt: url, with: config, position: .top ) // Render at custom offset (1/3 from top) let customWaveform = WaveformImageDrawer().waveformImage( fromAudioAt: url, with: config, position: .custom(0.333) ) ``` -------------------------------- ### WaveformLiveCanvas Example Usage Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/SwiftUIViews.md Demonstrates how to use WaveformLiveCanvas in a SwiftUI view. The samples array should be updated as audio recording progresses, and the WaveformLiveCanvas will re-render automatically. A button is provided to initiate the recording process. ```swift @State var samples: [Float] = [] var body: some View { VStack { WaveformLiveCanvas(samples: samples) Button("Record") { startRecording() } } } func startRecording() { // Update samples as recording progresses // WaveformLiveCanvas re-renders automatically } ``` -------------------------------- ### Update WaveformImageView Configuration on Main Thread Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/UIKitViews.md Ensure all UI updates and property access for WaveformImageView and WaveformLiveView occur on the main thread. This example shows how to safely update the configuration asynchronously. ```swift DispatchQueue.main.async { self.waveformView.configuration = newConfig } ``` -------------------------------- ### Circular Waveform Rendering Examples Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/README.md Employ CircularWaveformRenderer to display waveforms in a circular pattern. Use '.circle' for a filled disk or '.ring(innerFraction)' to create an annulus with a configurable inner hole. ```swift WaveformView(audioURL: url, renderer: CircularWaveformRenderer(kind: .circle)) WaveformView(audioURL: url, renderer: CircularWaveformRenderer(kind: .ring(0.5))) ``` -------------------------------- ### Linear Waveform Rendering Examples Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/README.md Use LinearWaveformRenderer for a standard horizontal amplitude envelope. Configure the 'sides' parameter for top-only or default display. The '.stereo' factory is available for interpreting two-channel audio data. ```swift WaveformView(audioURL: url, renderer: LinearWaveformRenderer()) // default WaveformView(audioURL: url, renderer: LinearWaveformRenderer(sides: .up)) // top-only WaveformView(audioURL: url, renderer: LinearWaveformRenderer.stereo) // stereo ``` -------------------------------- ### Initialization Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/WaveformAnalyzer.md Creates a stateless WaveformAnalyzer instance. Audio source is provided during analysis. ```APIDOC ## Initialization ```swift public init() ``` Creates a stateless analyzer. Takes the audio URL in the analysis method, not the constructor. **Example:** ```swift let analyzer = WaveformAnalyzer() ``` ``` -------------------------------- ### Initialize WaveformLiveView Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/UIKitViews.md Creates a live waveform view with optional custom configuration and renderer. Use this when setting up the view for live audio visualization. ```swift let liveView = WaveformLiveView( configuration: WaveformLiveView.defaultConfiguration, renderer: LinearWaveformRenderer() ) self.view.addSubview(liveView) ``` -------------------------------- ### Basic Styled Configuration Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Configure the waveform with size and a basic filled color style. ```swift Waveform.Configuration( size: CGSize(width: 500, height: 100), style: .filled(.blue) ) ``` -------------------------------- ### Full Control Configuration Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Configure all available parameters for maximum control over waveform appearance, including background, gradient style, damping, scaling, and antialiasing. ```swift Waveform.Configuration( size: CGSize(width: 500, height: 100), backgroundColor: .white, style: .gradient([.blue, .purple]), damping: .init(percentage: 0.15, sides: .both), scale: 2, verticalScalingFactor: 0.9, amplitudeScaling: .normalized, shouldAntialias: true ) ``` -------------------------------- ### Reset WaveformLiveView Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/UIKitViews.md Clears all accumulated samples, effectively emptying the waveform view. Use this when starting a new recording or resetting the visualization. ```swift liveView.reset() ``` -------------------------------- ### Configuration Constructor Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/types.md Initializes a Configuration struct with various rendering parameters. Default values are provided for common settings. ```swift public init( size: CGSize = .zero, backgroundColor: DSColor = DSColor.clear, style: Style = .gradient([DSColor.black, DSColor.gray]), damping: Damping? = nil, scale: CGFloat = DSScreen.scale, verticalScalingFactor: CGFloat = 0.95, amplitudeScaling: AmplitudeScaling = .absolute, shouldAntialias: Bool = false ) ``` -------------------------------- ### Handle Waveform Generation Error Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/errors.md Catch and handle the specific WaveformImageDrawer.GenerationError.generic case when image generation fails. This example shows how to display a user-friendly error message. ```swift do { let image = try await drawer.waveformImage( fromAudioAt: url, with: configuration ) imageView.image = image } catch WaveformImageDrawer.GenerationError.generic { print("Failed to generate waveform image") showErrorAlert(title: "Waveform Error", message: "Could not render waveform") } ``` -------------------------------- ### WaveformView - With Placeholder Init Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/SwiftUIViews.md Initializes WaveformView with a placeholder view that is displayed while the audio is being analyzed. This provides a better user experience during loading. ```APIDOC ## WaveformView - With Placeholder Init ### Description Convenience overload that shows a placeholder during loading and the styled waveform once ready. This is useful for providing visual feedback while the audio data is being processed. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **audioURL** (`URL`) - Required - Audio URL to analyze. - **configuration** (`Waveform.Configuration`) - Optional - Default with damping. Rendering configuration. - **renderer** (`WaveformRenderer`) - Optional - Default `LinearWaveformRenderer()`. Rendering strategy. - **priority** (`TaskPriority`) - Optional - Default `.userInitiated`. Task priority. - **placeholder** (`() -> Placeholder`) - Required - ViewBuilder for loading UI. ### Request Example ```swift WaveformView(audioURL: url) { ProgressView() } ``` ### Response #### Success Response (200) - **WaveformView<_ConditionalContent>** (`View`) - Shows placeholder while loading. ``` -------------------------------- ### Import Core Library Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/README.md Import the core DSWaveformImage library to access audio analysis, image rendering, and type definitions. ```swift import DSWaveformImage ``` -------------------------------- ### Live Rendering Configuration with Damping Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Creates a configuration suitable for live rendering, featuring a solid blue color and specified damping. ```swift Waveform.Configuration( style: .filled(.blue), damping: .init(percentage: 0.125, sides: .both) ) ``` -------------------------------- ### Initialize WaveformAnalyzer Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/WaveformAnalyzer.md Creates a stateless WaveformAnalyzer instance. The audio source is provided during analysis, not initialization. ```swift let analyzer = WaveformAnalyzer() ``` -------------------------------- ### samples(fromAsset:count:channelSelection:qos:) Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/WaveformAnalyzer.md Analyzes an in-memory AVAsset to extract the amplitude envelope, supporting configurable channel selection and QoS. ```APIDOC ### samples(fromAsset:count:channelSelection:qos:) ```swift public func samples( fromAsset audioAsset: AVAsset, count: Int, channelSelection: Waveform.ChannelSelection = .merged, qos: DispatchQoS.QoSClass = .userInitiated ) async throws -> [Float] ``` Analyzes an in-memory `AVAsset` instead of a file URL. | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `audioAsset` | `AVAsset` | — | Audio asset to process. | | `count` | `Int` | — | Number of output samples. | | `channelSelection` | `Waveform.ChannelSelection` | `.merged` | Channel selection mode. | | `qos` | `DispatchQoS.QoSClass` | `.userInitiated` | Dispatch QoS. | **Returns:** `[Float]` — Normalized amplitude envelope. ``` -------------------------------- ### Live Recording Configuration Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Configure waveform appearance for live recording scenarios, focusing on style and damping. ```swift Waveform.Configuration( style: .filled(.systemBlue), damping: .init(percentage: 0.125, sides: .both) ) ``` -------------------------------- ### WaveformView - Default Styled Init Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/SwiftUIViews.md A convenience initializer for WaveformView that automatically applies styling based on the provided configuration. Ideal for quick integration without explicit styling. ```APIDOC ## WaveformView - Default Styled Init ### Description Convenience overload that auto-styles the shape using the configuration's style. This initializer is useful for quickly displaying a waveform with predefined styles. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **audioURL** (`URL`) - Required - Audio URL to analyze. - **configuration** (`Waveform.Configuration`) - Optional - Default with damping. Rendering configuration. - **renderer** (`WaveformRenderer`) - Optional - Default `LinearWaveformRenderer()`. Rendering strategy. - **priority** (`TaskPriority`) - Optional - Default `.userInitiated`. Task priority. ### Request Example ```swift WaveformView( audioURL: url, configuration: .init(size: CGSize(width: 500, height: 100), style: .filled(.blue)) ) ``` ### Response #### Success Response (200) - **WaveformView** (`View`) - Renders using `configuration.style` automatically. ``` -------------------------------- ### WaveformLiveCanvas Initialization Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/SwiftUIViews.md Initializes a WaveformLiveCanvas view with audio samples, configuration, a renderer, and an option to draw silence padding. ```APIDOC ## WaveformLiveCanvas ### Description Real-time waveform visualization for live audio streams (recording, live input, etc.). Renders a `[Float]` sample stream using SwiftUI `Canvas`. ### Initialization ```swift public init( samples: [Float], configuration: Waveform.Configuration = defaultConfiguration, renderer: WaveformRenderer = LinearWaveformRenderer(), shouldDrawSilencePadding: Bool = false ) ``` Creates a live canvas view. #### Parameters - **samples** (`[Float]`) - Required - Current samples to render. Update this binding to trigger re-draws. - **configuration** (`Waveform.Configuration`) - Optional - Rendering parameters. Defaults to `defaultConfiguration` with damping. - **renderer** (`WaveformRenderer`) - Optional - Rendering strategy. Defaults to `LinearWaveformRenderer()`. - **shouldDrawSilencePadding** (`Bool`) - Optional - If `true`, draw a zero line at the bottom while samples are still filling the view width. Defaults to `false`. ### Static Property ```swift public static let defaultConfiguration = Waveform.Configuration( damping: .init(percentage: 0.125, sides: .both) ) ``` Default configuration with damping enabled for smoother live rendering. ### Behavior **Rendering:** - Renders the `samples` array into a SwiftUI `Canvas` asynchronously. - Samples are clipped to the view width; as new samples arrive, older ones scroll left. - Uses the renderer's `lastOffset` tracking to avoid flickering. **Silence Padding:** - When `shouldDrawSilencePadding == true`, a silence line (amplitude `1.0`) is drawn on the left until samples fill the view. - Useful for recording views to show a baseline. **Responsiveness:** - The view re-renders whenever `samples` changes (via `@State` observation). - No debounce; suitable for smooth animations at normal frame rates. ``` -------------------------------- ### Solid Color Configuration Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Creates a configuration for a solid color waveform. ```swift Waveform.Configuration(style: .filled(.blue)) ``` -------------------------------- ### WaveformLiveView Initialization Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/UIKitViews.md Initializes a WaveformLiveView with optional configuration and renderer. ```APIDOC ## WaveformLiveView Initialization ### Description Creates a live waveform view with customizable rendering parameters. ### Parameters #### Initializer Parameters - **configuration** (`Waveform.Configuration`) - Optional - Default with damping - Rendering parameters. - **renderer** (`WaveformRenderer`) - Optional - `LinearWaveformRenderer()` - Rendering strategy. ### Example ```swift let liveView = WaveformLiveView( configuration: WaveformLiveView.defaultConfiguration, renderer: LinearWaveformRenderer() ) self.view.addSubview(liveView) ``` ``` -------------------------------- ### Configuration Builder Method Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/types.md Returns a copy of the Configuration struct with specified properties replaced. This facilitates immutable updates to rendering settings. ```swift public func with( size: CGSize? = nil, backgroundColor: DSColor? = nil, style: Style? = nil, damping: Damping? = nil, scale: CGFloat? = nil, verticalScalingFactor: CGFloat? = nil, amplitudeScaling: AmplitudeScaling? = nil, shouldAntialias: Bool? = nil ) -> Configuration ``` -------------------------------- ### WaveformView - Full Init with ViewBuilder Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/SwiftUIViews.md Initializes WaveformView with a custom styling closure. This allows for complete control over the waveform's appearance by providing the underlying WaveformShape to a ViewBuilder. ```APIDOC ## WaveformView - Full Init with ViewBuilder ### Description Creates a view that analyzes the audio and passes the underlying `WaveformShape` to a custom styling closure. This enables detailed customization of the waveform's appearance. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **audioURL** (`URL`) - Required - Local filesystem URL of the audio file to analyze. - **configuration** (`Waveform.Configuration`) - Optional - Default with damping enabled. Rendering parameters (size, style, scale, etc.). - **renderer** (`WaveformRenderer`) - Optional - Default `LinearWaveformRenderer()`. Rendering strategy. Can be `CircularWaveformRenderer` or custom. - **priority** (`TaskPriority`) - Optional - Default `.userInitiated`. Task priority for background analysis. - **content** (`(WaveformShape) -> Content`) - Required - ViewBuilder closure that receives the underlying shape. Apply any `ShapeStyle` (`.fill()`, `.stroke()`, gradients, masks, etc.). ### Request Example ```swift WaveformView(audioURL: url) { shape in shape.fill(.blue) } ``` ### Response #### Success Response (200) - **WaveformView** (`View`) - A `View` that analyzes the URL and renders with custom styling. ``` -------------------------------- ### SpectralAnalysis Constructor Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/types.md Initializes a SpectralAnalysis struct with normalized amplitude envelope and spectral centroid data. ```swift public init(amplitudes: [Float], spectralCentroids: [Float]) ``` -------------------------------- ### samples(fromAudioAt:count:channelSelection:qos:) Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/WaveformAnalyzer.md Calculates the amplitude envelope from a local audio file URL. Supports various channel selections and asynchronous execution. ```APIDOC ## Public Methods ### samples(fromAudioAt:count:channelSelection:qos:) ```swift public func samples( fromAudioAt audioAssetURL: URL, count: Int, channelSelection: Waveform.ChannelSelection = .merged, qos: DispatchQoS.QoSClass = .userInitiated ) async throws -> [Float] ``` Calculates the amplitude envelope from an audio file URL. | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `audioAssetURL` | `URL` | — | Local filesystem URL of the audio file. | | `count` | `Int` | — | Number of output samples (per rendered channel slot). For `.merged` and `.specific`, this is the array length; for `.stereo`, result is `count * 2` (left then right). | | `channelSelection` | `Waveform.ChannelSelection` | `.merged` | Which channel(s) to extract: `.merged` (default, all channels combined), `.specific(index)` (single channel), or `.stereo` (L/R concatenated). | | `qos` | `DispatchQoS.QoSClass` | `.userInitiated` | Dispatch QoS for background analysis. | **Returns:** `[Float]` — Normalized samples in `[0, 1]` where `0` is maximum amplitude and `1` is silence. **Throws:** `AnalyzeError` — If the file is unreadable, track is missing, or channel index is invalid. **Example:** ```swift let analyzer = WaveformAnalyzer() let samples = try await analyzer.samples( fromAudioAt: audioURL, count: 1024, channelSelection: .merged ) // Use samples for rendering ``` ``` -------------------------------- ### WaveformView Initialization with Placeholder Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/SwiftUIViews.md Use this overload to display a placeholder view while the waveform is being analyzed. The placeholder is replaced by the waveform once it's ready. ```swift @available(iOS 15.0, macOS 12.0, *) public init( audioURL: URL, configuration: Waveform.Configuration = Waveform.Configuration(damping: .init(percentage: 0.125, sides: .both)), renderer: WaveformRenderer = LinearWaveformRenderer(), priority: TaskPriority = .userInitiated, @ViewBuilder placeholder: @escaping () -> Placeholder ) where Content == _ConditionalContent ``` ```swift WaveformView(audioURL: url) { ProgressView() } ``` -------------------------------- ### Initialize WaveformImageView Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/UIKitViews.md Creates a waveform image view with the provided frame. Use this to instantiate the view programmatically. ```swift let view = WaveformImageView(frame: CGRect(x: 0, y: 0, width: 500, height: 100)) view.waveformAudioURL = audioURL // Image is automatically loaded and rendered ``` -------------------------------- ### Import DSWaveformImage Modules Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/README.md Import the necessary DSWaveformImage modules into your project. Import 'DSWaveformImage' for core functionality and 'DSWaveformImageViews' for UI components. ```swift import DSWaveformImage // core: drawer, analyzer, renderers, types import DSWaveformImageViews // UIKit + SwiftUI views (optional) ``` -------------------------------- ### Live Waveform Recording Interface Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/UIKitViews.md Implement a live recording interface using WaveformLiveView and AVAudioRecorder. This view updates in real-time to visualize the audio being recorded. ```swift import UIKit import AVFoundation import DSWaveformImage import DSWaveformImageViews class LiveRecordingViewController: UIViewController { let liveWaveformView = WaveformLiveView() var recorder: AVAudioRecorder? var displayLink: CADisplayLink? override func viewDidLoad() { super.viewDidLoad() liveWaveformView.frame = CGRect(x: 20, y: 100, width: 335, height: 150) liveWaveformView.shouldDrawSilencePadding = true view.addSubview(liveWaveformView) setupRecorder() } func setupRecorder() { let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] .appendingPathComponent("recording.m4a") let settings: [String: Any] = [ AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 44100.0, AVNumberOfChannelsKey: 1 ] recorder = try? AVAudioRecorder(url: url, settings: settings) recorder?.delegate = self } @IBAction func startRecording(_ sender: UIButton) { recorder?.record() liveWaveformView.reset() // Use display link for smooth meter updates displayLink = CADisplayLink( target: self, selector: #selector(updateMeters) ) displayLink?.preferredFramesPerSecond = 30 displayLink?.add(to: .main, forMode: .common) } @objc func updateMeters() { guard let recorder = recorder else { return } recorder.updateMeters() let power = recorder.averagePower(forChannel: 0) let normalized = 1 - pow(10, power / 20) liveWaveformView.add(sample: normalized) } @IBAction func stopRecording(_ sender: UIButton) { recorder?.stop() displayLink?.invalidate() } } ``` -------------------------------- ### WaveformLiveCanvas Initialization Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/SwiftUIViews.md Initializes a WaveformLiveCanvas view with samples, configuration, renderer, and silence padding option. Update the samples binding to trigger re-renders. The default configuration includes damping for smoother live rendering. ```swift @available(iOS 15.0, macOS 12.0, *) public struct WaveformLiveCanvas: View ``` ```swift public init( samples: [Float], configuration: Waveform.Configuration = defaultConfiguration, renderer: WaveformRenderer = LinearWaveformRenderer(), shouldDrawSilencePadding: Bool = false ) ``` -------------------------------- ### Spectral Visualization Configuration Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Configure waveform for spectral visualization, specifying size, gradient style for low and high frequencies, and vertical scaling. ```swift Waveform.Configuration( size: CGSize(width: 500, height: 100), style: .spectralTint(low: .systemBlue, high: .systemRed), verticalScalingFactor: 1.0 ) ``` -------------------------------- ### Live Recording Visualization (UIKit) Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/README.md Use WaveformLiveView to visualize live audio recording data in UIKit. Add samples as the recording progresses. ```swift let liveView = WaveformLiveView() recorder.updateMeters() let amplitude = 1 - pow(10, recorder.averagePower(forChannel: 0) / 20) liveView.add(sample: amplitude) ``` -------------------------------- ### Initialize LinearWaveformRenderer Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/Renderers.md Creates a standard single-waveform renderer. Configure which side(s) of the centerline to render and how to select channels. ```swift let renderer = LinearWaveformRenderer(sides: .both, channelSelection: .merged) ``` -------------------------------- ### Import Views Library Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/README.md Optionally import the DSWaveformImageViews library to use SwiftUI or UIKit views for waveform visualization. ```swift import DSWaveformImageViews ``` -------------------------------- ### High-DPI Output Configuration Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Creates a configuration for high-resolution export, specifying a scale factor of 3 for High-DPI output. ```swift Waveform.Configuration( size: CGSize(width: 500, height: 100), scale: 3 // for printing or high-resolution export ) ``` -------------------------------- ### samples(fromAudioAt:count:qos:) Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/WaveformAnalyzer.md A convenience overload for calculating the amplitude envelope from an audio file URL, defaulting to merged channel selection. ```APIDOC ### samples(fromAudioAt:count:qos:) ```swift public func samples( fromAudioAt audioAssetURL: URL, count: Int, qos: DispatchQoS.QoSClass = .userInitiated ) async throws -> [Float] ``` Convenience overload; equivalent to calling with `channelSelection: .merged`. | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `audioAssetURL` | `URL` | — | Local filesystem URL of the audio file. | | `count` | `Int` | — | Number of output samples. | | `qos` | `DispatchQoS.QoSClass` | `.userInitiated` | Dispatch QoS. | **Returns:** `[Float]` — Normalized amplitude envelope. ``` -------------------------------- ### SwiftUI Views API Reference Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/README.md Documentation for SwiftUI views including WaveformView, WaveformShape, and WaveformLiveCanvas for declarative UI implementation. ```APIDOC ## SwiftUI Views ### Description Provides declarative SwiftUI views for displaying audio waveforms. Includes `WaveformView` for static waveforms, `WaveformShape` for custom drawing, and `WaveformLiveCanvas` for real-time updates. ### Usage Integrate these views into your SwiftUI applications for waveform visualization. ### Related Documentation - [UIKit Views](api-reference/UIKitViews.md) ``` -------------------------------- ### Configuration Struct Definition Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/types.md Defines comprehensive settings for rendering waveform images. This struct is passed to all renderers and the drawer. ```swift public struct Configuration: Equatable, Sendable ``` -------------------------------- ### Waveform.Configuration Builder Pattern Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Creates a modified copy of an existing Configuration object using the `with(...)` method. Returns a new Configuration with specified properties replaced, others unchanged. ```swift public func with( size: CGSize? = nil, backgroundColor: DSColor? = nil, style: Style? = nil, damping: Damping? = nil, scale: CGFloat? = nil, verticalScalingFactor: CGFloat? = nil, amplitudeScaling: AmplitudeScaling? = nil, shouldAntialias: Bool? = nil ) -> Configuration ``` ```swift let baseConfig = Waveform.Configuration(size: CGSize(width: 500, height: 100)) let blueConfig = baseConfig.with(style: .filled(.systemBlue)) let dampedConfig = blueConfig.with(damping: .init(percentage: 0.2)) ``` -------------------------------- ### Live Recording Waveform Visualization Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/SwiftUIViews.md This view displays a live audio waveform during recording. It requires a binding to an array of Float samples and can optionally draw silence padding. ```swift struct LiveRecordingView: View { @State var samples: [Float] = [] var body: some View { VStack { WaveformLiveCanvas( samples: samples, shouldDrawSilencePadding: true ) .frame(height: 100) Button("Start Recording") { AVAudioRecorder.startRecording { newSample in samples.append(newSample) } } } } } ``` -------------------------------- ### WaveformImageView Initialization Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/UIKitViews.md Initializes a WaveformImageView with a specified frame. This view automatically analyzes and renders a waveform from an audio URL. ```APIDOC ## WaveformImageView Initialization ### Description Creates a waveform image view with the provided frame. This view automatically analyzes and renders a waveform from an audio URL. ### Method Signature ```swift override public init(frame: CGRect) required public init?(coder aDecoder: NSCoder) ``` ### Example ```swift let view = WaveformImageView(frame: CGRect(x: 0, y: 0, width: 500, height: 100)) view.waveformAudioURL = audioURL // Image is automatically loaded and rendered ``` ``` -------------------------------- ### Spectral Tint Configuration Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Creates a configuration for a spectral tint waveform, using specified low and high colors. ```swift Waveform.Configuration( size: CGSize(width: 500, height: 100), style: .spectralTint(low: .systemBlue, high: .systemRed) ) ``` -------------------------------- ### Normalized Amplitude Configuration Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Creates a configuration where the amplitude scaling is set to normalized, ensuring every file fills the canvas. ```swift Waveform.Configuration( amplitudeScaling: .normalized ) ``` -------------------------------- ### WaveformLiveView Methods Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/UIKitViews.md Methods for adding samples and resetting the waveform visualization. ```APIDOC ## WaveformLiveView Methods ### add(sample:) #### Description Appends a single sample and re-draws the waveform. #### Parameters - **sample** (`Float`) - Normalized amplitude in `(0...1)` where `0` is loudest and `1` is silence. #### Behavior - The new sample is appended to the internal sample array. - The view immediately re-draws (does not debounce). - Samples scroll left as new ones arrive, keeping the rightmost samples visible. #### Example ```swift // From AVAudioRecorder in a meter update callback recorder.updateMeters() let amplitude = 1 - pow(10, recorder.averagePower(forChannel: 0) / 20) liveView.add(sample: amplitude) ``` ### add(samples:) #### Description Appends multiple samples and re-draws the waveform. #### Parameters - **samples** (`[Float]`) - Array of normalized amplitudes. #### Behavior - All samples are appended in order. - The view re-draws once after all samples are added. - Preferred over repeated calls to `add(sample:)` for better performance. #### Example ```swift let newSamples = extractSamplesFromBuffer(audioBuffer) liveView.add(samples: newSamples) ``` ### reset() #### Description Clears all samples, emptying the view. #### Example ```swift liveView.reset() ``` ``` -------------------------------- ### Handle Waveform Analysis Errors Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/README.md Demonstrates how to handle potential errors during audio analysis, including specific cases like empty tracks or generic failures. ```swift do { let samples = try await analyzer.samples(fromAudioAt: url, count: 1024) } catch WaveformAnalyzer.AnalyzeError.emptyTracks { print("No audio in file") } catch { print("Analysis failed: \(error)") } ``` -------------------------------- ### WaveformLiveView Static Property Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/UIKitViews.md Default configuration for WaveformLiveView. ```APIDOC ## WaveformLiveView Static Property ### defaultConfiguration Default configuration with damping enabled for smooth live rendering. ```swift public static let defaultConfiguration = Waveform.Configuration( damping: .init(percentage: 0.125, sides: .both) ) ``` ``` -------------------------------- ### Waveform.Configuration Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/types.md Comprehensive configuration for rendering waveforms, including size, colors, style, and damping. ```APIDOC ## Waveform.Configuration ### Description Provides comprehensive rendering configuration passed to all renderers and the drawer. ### Properties - **size** (`CGSize`) - Default: `.zero` - Output image dimensions. - **backgroundColor** (`DSColor`) - Default: `.clear` - Background fill color. - **style** (`Style`) - Default: `.gradient([.black, .gray])` - How the envelope is drawn. - **damping** (`Damping?`) - Default: `nil` - Optional fade at edges. - **scale** (`CGFloat`) - Default: `DSScreen.scale` - Device scale factor (e.g., `2` for retina, `3` for iPhone 6+). - **verticalScalingFactor** (`CGFloat`) - Default: `0.95` - Amplitude-to-height multiplier. `1.0` = full available space. `> 1.0` allows clipping. - **amplitudeScaling** (`AmplitudeScaling`) - Default: `.absolute` - How amplitude maps to canvas height. - **shouldAntialias** (`Bool`) - Default: `false` - Enable antialiasing (may reduce opacity). ### Computed Properties - **shouldDamp** (`Bool`) - Returns `true` if damping is configured (`damping != nil`). ### Constructor ```swift public init(size: CGSize = .zero, backgroundColor: DSColor = DSColor.clear, style: Style = .gradient([DSColor.black, DSColor.gray]), damping: Damping? = nil, scale: CGFloat = DSScreen.scale, verticalScalingFactor: CGFloat = 0.95, amplitudeScaling: AmplitudeScaling = .absolute, shouldAntialias: Bool = false) ``` ### Builder Method ```swift public func with(size: CGSize? = nil, backgroundColor: DSColor? = nil, style: Style? = nil, damping: Damping? = nil, scale: CGFloat? = nil, verticalScalingFactor: CGFloat? = nil, amplitudeScaling: AmplitudeScaling? = nil, shouldAntialias: Bool? = nil) -> Configuration ``` ### Validation `verticalScalingFactor` must be `> 0` or a precondition fails. ``` -------------------------------- ### Spectral Visualization Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/README.md Generate a spectral visualization of an audio file using WaveformImageDrawer with a specific configuration for spectral tinting. ```swift let config = Waveform.Configuration( style: .spectralTint(low: .systemBlue, high: .systemRed) ) let image = try await WaveformImageDrawer().waveformImage(fromAudioAt: url, with: config) ``` -------------------------------- ### waveformImage(fromAudioAt:with:renderer:position:qos:) Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/WaveformImageDrawer.md Analyzes an audio file and renders a complete waveform image in one asynchronous call. This method is suitable for generating static waveform images from existing audio files. ```APIDOC ## waveformImage(fromAudioAt:with:renderer:position:qos:) ### Description Analyzes an audio file and renders a complete waveform image in one call. This method is suitable for generating static waveform images from existing audio files. ### Method `async throws` ### Parameters #### Path Parameters - **audioAssetURL** (`URL`) - Required - Local filesystem URL of the audio file. - **with** (`Waveform.Configuration`) - Required - Rendering configuration (size, style, damping, scaling, etc.). - **renderer** (`WaveformRenderer`) - Optional - Rendering strategy. Options: `LinearWaveformRenderer`, `CircularWaveformRenderer`, or custom. Defaults to `LinearWaveformRenderer()`. - **position** (`Waveform.Position`) - Optional - Vertical positioning of the waveform within the image. Defaults to `.middle`. - **qos** (`DispatchQoS.QoSClass`) - Optional - Dispatch QoS for the background analysis task. Defaults to `.userInitiated`. ### Returns `DSImage` - `UIImage` on iOS/visionOS, `NSImage` on macOS. Size and scale determined by `configuration.size` and `configuration.scale`. ### Throws `GenerationError` or `WaveformAnalyzer.AnalyzeError` - If analysis fails or image rendering fails. ### Example ```swift let drawer = WaveformImageDrawer() let image = try await drawer.waveformImage( fromAudioAt: audioURL, with: Waveform.Configuration( size: CGSize(width: 500, height: 100), style: .filled(.blue) ) ) imageView.image = image ``` ``` -------------------------------- ### Download Audio Before Analysis Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/errors.md DSWaveformImage requires local audio files. Download remote audio first using a separate function before passing the local URL to the analyzer. ```swift // Download audio first let localURL = try await downloadAudio(from: remoteURL) // Then analyze let samples = try await analyzer.samples(fromAudioAt: localURL, count: 1024) ``` -------------------------------- ### Configure Striped Waveform Style Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/types.md Configuration for `.striped` style rendering, defining stripe color, width, spacing, and line cap style. Default values are provided for convenience. ```swift public struct StripeConfig: Equatable, Sendable ``` ```swift public init(color: DSColor, width: CGFloat = 1, spacing: CGFloat = 5, lineCap: CGLineCap = .round) ``` -------------------------------- ### Direct WaveformShape Styling Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/README.md Instantiate `WaveformShape` directly with audio samples to apply custom styling, such as filling it with a specific color. This is useful when you already have the audio samples processed. ```swift WaveformShape(samples: samples).fill(.indigo) ``` -------------------------------- ### Pre-configured Stereo Renderer Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/Renderers.md A static property providing a pre-configured renderer specifically for stereo two-channel audio. It automatically handles splitting left and right channels for rendering. ```swift WaveformView(audioURL: url, renderer: LinearWaveformRenderer.stereo) ``` -------------------------------- ### Test File Not Found Error Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/errors.md Catch WaveformAnalyzer.AnalyzeError.readerError when attempting to analyze a non-existent audio file. ```swift // Create an invalid URL let badURL = URL(fileURLWithPath: "/nonexistent/audio.mp3") do { let samples = try await analyzer.samples(fromAudioAt: badURL, count: 1024) } catch WaveformAnalyzer.AnalyzeError.readerError { print("✓ Correctly caught reader error for missing file") } ``` -------------------------------- ### LinearWaveformRenderer Initialization Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/Renderers.md Initializes a LinearWaveformRenderer with specified sides and channel selection. The default is to draw both sides of the centerline for all channels. ```APIDOC ## init(sides:channelSelection:) ### Description Creates a standard single-waveform renderer. ### Parameters #### Path Parameters - `sides` (Sides) - Required - Which side(s) of centerline to render. Defaults to `.both`. - `channelSelection` (Waveform.SingleChannelSelection) - Required - `.merged` (all channels) or `.specific(index)` (single channel). Defaults to `.merged`. ### Request Example ```swift let renderer = LinearWaveformRenderer(sides: .both, channelSelection: .merged) ``` ``` -------------------------------- ### Initialize WaveformShape Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/SwiftUIViews.md Creates a WaveformShape instance using normalized amplitude samples, rendering configuration, and a specified renderer. Ensure samples are normalized to [0, 1] and match the expected layout for stereo renderers. ```swift let shape = WaveformShape(samples: samples, configuration: config) ``` -------------------------------- ### UIKit Views API Reference Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/README.md Documentation for UIKit views including WaveformImageView and WaveformLiveView for building waveform visualizations in UIKit-based applications. ```APIDOC ## UIKit Views ### Description Offers UIKit-compatible views for displaying audio waveforms. Includes `WaveformImageView` for static waveform rendering and `WaveformLiveView` for live updates. ### Usage Use these views within your iOS, iPadOS, and macOS applications built with UIKit. ### Related Documentation - [SwiftUI Views](api-reference/SwiftUIViews.md) ``` -------------------------------- ### Deprecated samples Method with Completion Handler Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/WaveformAnalyzer.md This is a deprecated callback-based API for retrieving waveform samples. It is recommended to use the asynchronous overload instead. ```swift @available(*, deprecated, renamed: "samples(fromAudioAt:count:qos:)") public func samples( fromAudioAt audioAssetURL: URL, count: Int, qos: DispatchQoS.QoSClass = .userInitiated, completionHandler: @escaping (Result<[Float], Error>) -> () ) ``` -------------------------------- ### WaveformView Initialization with ViewBuilder Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/SwiftUIViews.md Use this initializer to pass a custom styling closure that receives the underlying WaveformShape. Apply any ShapeStyle like .fill(), .stroke(), or gradients within this closure. ```swift public init( audioURL: URL, configuration: Waveform.Configuration = Waveform.Configuration(damping: .init(percentage: 0.125, sides: .both)), renderer: WaveformRenderer = LinearWaveformRenderer(), priority: TaskPriority = .userInitiated, @ViewBuilder content: @escaping (WaveformShape) -> Content ) ``` ```swift WaveformView(audioURL: url) { shape in shape.fill(.blue) } ``` -------------------------------- ### analyze(fromAudioAt:count:bandsPerOctave:minFrequency:channelSelection:qos:) Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/WaveformAnalyzer.md Computes both amplitude envelope and spectral centroids from an audio file URL in a single pass, useful for spectrum-aware visualizations. ```APIDOC ### analyze(fromAudioAt:count:bandsPerOctave:minFrequency:channelSelection:qos:) ```swift public func analyze( fromAudioAt audioAssetURL: URL, count: Int, bandsPerOctave: Int = 4, minFrequency: Float = 50, channelSelection: Waveform.ChannelSelection = .merged, qos: DispatchQoS.QoSClass = .userInitiated ) async throws -> Waveform.SpectralAnalysis ``` Computes both amplitude envelope and spectral centroids in a single pass. Use this when driving `Waveform.Style.spectralTint` or other spectrum-aware visualizations. | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `audioAssetURL` | `URL` | — | Local filesystem URL of the audio file. | | `count` | `Int` | — | Number of output amplitude/centroid slots. | | `bandsPerOctave` | `Int` | `4` | Log-spaced FFT frequency resolution. `4` = quarter-octave (musically meaningful, computationally cheap). | | `minFrequency` | `Float` | `50` | Lower frequency bound of the log scale (Hz). `50` Hz brushes the bottom of bass range without rumble. | | `channelSelection` | `Waveform.ChannelSelection` | `.merged` | Channel selection mode. | | `qos` | `DispatchQoS.QoSClass` | `.userInitiated` | Dispatch QoS. | **Returns:** `Waveform.SpectralAnalysis` — Contains `amplitudes` and `spectralCentroids` arrays of equal length. **Throws:** `AnalyzeError` — Same conditions as `samples(...)`. **Example:** ```swift let analysis = try await analyzer.analyze( fromAudioAt: url, count: 1024, bandsPerOctave: 4, minFrequency: 50 ) // Use analysis.amplitudes for the envelope // Use analysis.spectralCentroids to color each slot based on frequency content ``` ``` -------------------------------- ### Displaying a Static Waveform Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/UIKitViews.md Use WaveformImageView to display a static waveform from an audio file. Configure the appearance using Waveform.Configuration. ```swift import UIKit import DSWaveformImage import DSWaveformImageViews class WaveformViewController: UIViewController { let waveformView = WaveformImageView() override func viewDidLoad() { super.viewDidLoad() waveformView.frame = CGRect(x: 20, y: 100, width: 300, height: 100) view.addSubview(waveformView) if let audioURL = Bundle.main.url(forResource: "audio", withExtension: "mp3") { waveformView.waveformAudioURL = audioURL waveformView.configuration = Waveform.Configuration( size: waveformView.bounds.size, style: .filled(.systemBlue) ) } } } ``` -------------------------------- ### Live Recording Visualization (SwiftUI) Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/README.md Use WaveformLiveCanvas to visualize live audio recording data in SwiftUI. Update the samples array as recording progresses. ```swift @State var samples: [Float] = [] WaveformLiveCanvas(samples: samples, shouldDrawSilencePadding: true) // Update samples as recording progresses ``` -------------------------------- ### CircularWaveformRenderer Initialization Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/Renderers.md Creates a circular renderer with a specified kind. Defaults to a filled circle. ```swift public init(kind: Kind = .circle) ``` -------------------------------- ### Configure WaveformImageView Rendering Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/UIKitViews.md Customize the waveform's appearance by providing a Waveform.Configuration object. Changing this property re-renders the waveform automatically. ```swift view.configuration = Waveform.Configuration( size: view.bounds.size, style: .filled(.blue) ) // Waveform re-renders automatically ``` -------------------------------- ### Default Gradient Configuration Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/configuration.md Creates a default configuration for a gradient waveform with damping disabled. ```swift Waveform.Configuration() // gradient with damping disabled ``` -------------------------------- ### WaveformView Default Styled Initialization Source: https://github.com/dmrschmidt/dswaveformimage/blob/main/_autodocs/api-reference/SwiftUIViews.md This convenience overload automatically styles the waveform using the configuration's style. It's useful for quick integration when custom shape styling is not required. ```swift @available(iOS 15.0, macOS 12.0, *) public init( audioURL: URL, configuration: Waveform.Configuration = Waveform.Configuration(damping: .init(percentage: 0.125, sides: .both)), renderer: WaveformRenderer = LinearWaveformRenderer(), priority: TaskPriority = .userInitiated ) where Content == AnyView ``` ```swift WaveformView( audioURL: url, configuration: .init(size: CGSize(width: 500, height: 100), style: .filled(.blue)) ) ```