Introduction to Subsonic
Subsonic is a compact and efficient library specifically designed to facilitate audio playback in SwiftUI applications. It gives developers the flexibility to handle audio in both an imperative style—where you instruct the program to "play this sound now"—and a declarative style, letting you "play this sound when some state becomes true." This makes managing audio playback intuitive and seamless within the SwiftUI framework.
Subsonic is compatible with iOS 14+, macOS 11+, tvOS 14+, and watchOS 7+. The name "Subsonic" reflects its minimal footprint; it's so lightweight and unobtrusive that it's virtually imperceptible.
Installation
To incorporate Subsonic into a Swift Package Manager (SwiftPM) project, you need to add a specific line to the dependencies section in your Package.swift
file:
.package(url: "https://github.com/twostraws/Subsonic", from: "0.2.0"),
Following this, the import Subsonic
statement should be included in your Swift files to access the library's capabilities.
Playing Sounds
Subsonic provides four distinct methods to play sounds, catering to varying levels of control:
Option 1: Simple Sound Playback
For a straightforward approach to play an audio file from your resources, use the play(sound:)
function within any view like so:
Button("Play Sound") {
play(sound: "example.mp3")
}
This command will locate example.mp3
in the main bundle and play it instantly. If you need to access files from a different bundle, you should explore additional options.
Option 2: Controlled Playback
To maintain precise control over the playback of a sound, create an @StateObject
property using a SubsonicPlayer
object:
struct ContentView: View {
@StateObject private var sound = SubsonicPlayer(sound: "example.mp3")
var body: some View {
VStack {
Button("Start") {
sound.play()
}
Button("Stop") {
sound.stop()
}
Slider(value: $sound.volume)
}
}
}
This setup allows you to play, stop, and modify the sound properties like volume and repeat count, as needed.
Option 3: State-Dependent Playback
To start or stop audio based on your app's state, use the sound()
modifier in your SwiftUI views and bind it to a state variable:
struct ContentView: View {
@State private var isPlaying = false
var body: some View {
Button {
isPlaying.toggle()
} label: {
Image(systemName: isPlaying ? "speaker.wave.3" : "speaker")
}
.sound("example.mp3", isPlaying: $isPlaying)
}
}
Option 4: Manual Sound Management
When you prefer to set up a sound without playing it immediately, use prepare(sound:)
to receive an AVAudioPlayer
object:
Button("Play Sound") {
let player = prepare(sound: "example.mp3")
// Configure and play when ready
}
Important: You must store the player
object from prepare(sound:)
to manage its playback. If this object is not stored, it will be deallocated, and playback will not occur.
Stopping Sounds
Stopping a sound varies based on how it was initiated:
- With
play(sound:)
, usestop(sound: "example.mp3")
to halt specific sounds orstopAllManagedSounds()
to cease all sounds initiated this way. - For a
SubsonicPlayer
instance, callstop()
on the player to stop its sounds. - The
sound()
modifier requires managing the state bound to it to control playback. - If
prepare(sound:)
was used, manually handle the playback and stopping process.
Important: stopAllManagedSounds()
doesn't affect sounds managed with SubsonicPlayer
, prepare(sound:)
, or the sound()
modifier—it only stops sounds that were played with play(sound:)
.
Options
Several optional parameters are available when using play(sound:)
and the sound()
modifier:
bundle
: Specifies the bundle containing the sound file, defaulting toBundle.main
.volume
: Adjusts the sound's loudness from 0 (silent) to 1 (maximum volume), with a default of 1.repeatCount
: Defines how many times a sound repeats: 0 plays it once, 1 plays it twice, etc. Use.continuous
for infinite repeats, defaulting to 0.
The sound()
modifier also includes the playMode
option, which dictates playback behavior upon resume. .reset
, the default setting, starts the sound from the beginning upon resume, while .continue
resumes playback from where it left off.
For prepare(sound:)
, you can similarly pass a custom bundle, defaulting to Bundle.main
.
If you're utilizing SubsonicPlayer
, you can set the bundle, volume, repeat count, and play mode during initialization, with the latter three also adjustable during runtime.
Credits
Subsonic was developed by Paul Hudson and is © 2021 Paul Hudson, available under the MIT license. For the full license, please refer to the LICENSE file. To explore more Swift tutorials, visit Paul Hudson’s site: Hacking with Swift.