vOOice/VoiceInk/SoundManager.swift

115 lines
3.3 KiB
Swift

import Foundation
import AVFoundation
import SwiftUI
@MainActor
class SoundManager: ObservableObject {
static let shared = SoundManager()
private var startSound: AVAudioPlayer?
private var stopSound: AVAudioPlayer?
private var escSound: AVAudioPlayer?
private var customStartSound: AVAudioPlayer?
private var customStopSound: AVAudioPlayer?
@AppStorage("isSoundFeedbackEnabled") private var isSoundFeedbackEnabled = true
private init() {
Task(priority: .background) {
await setupSounds()
}
NotificationCenter.default.addObserver(
self,
selector: #selector(reloadCustomSounds),
name: NSNotification.Name("CustomSoundsChanged"),
object: nil
)
}
func setupSounds() async {
if let startSoundURL = Bundle.main.url(forResource: "recstart", withExtension: "mp3"),
let stopSoundURL = Bundle.main.url(forResource: "recstop", withExtension: "mp3"),
let escSoundURL = Bundle.main.url(forResource: "esc", withExtension: "wav") {
try? await loadSounds(start: startSoundURL, stop: stopSoundURL, esc: escSoundURL)
}
await reloadCustomSoundsAsync()
}
@objc private func reloadCustomSounds() {
Task {
await reloadCustomSoundsAsync()
}
}
private func loadAndPreparePlayer(from url: URL?) -> AVAudioPlayer? {
guard let url = url else { return nil }
let player = try? AVAudioPlayer(contentsOf: url)
player?.volume = 0.4
player?.prepareToPlay()
return player
}
private func reloadCustomSoundsAsync() async {
customStartSound = loadAndPreparePlayer(from: CustomSoundManager.shared.getCustomSoundURL(for: .start))
customStopSound = loadAndPreparePlayer(from: CustomSoundManager.shared.getCustomSoundURL(for: .stop))
}
private func loadSounds(start startURL: URL, stop stopURL: URL, esc escURL: URL) async throws {
do {
startSound = try AVAudioPlayer(contentsOf: startURL)
stopSound = try AVAudioPlayer(contentsOf: stopURL)
escSound = try AVAudioPlayer(contentsOf: escURL)
await MainActor.run {
startSound?.prepareToPlay()
stopSound?.prepareToPlay()
escSound?.prepareToPlay()
}
startSound?.volume = 0.4
stopSound?.volume = 0.4
escSound?.volume = 0.3
} catch {
throw error
}
}
func playStartSound() {
guard isSoundFeedbackEnabled else { return }
if let custom = customStartSound {
custom.play()
} else {
startSound?.volume = 0.4
startSound?.play()
}
}
func playStopSound() {
guard isSoundFeedbackEnabled else { return }
if let custom = customStopSound {
custom.play()
} else {
stopSound?.volume = 0.4
stopSound?.play()
}
}
func playEscSound() {
guard isSoundFeedbackEnabled else { return }
escSound?.volume = 0.3
escSound?.play()
}
var isEnabled: Bool {
get { isSoundFeedbackEnabled }
set {
objectWillChange.send()
isSoundFeedbackEnabled = newValue
}
}
}