diff options
| author | Dustin Mierau <dustin@mierau.me> | 2025-11-08 17:21:54 -0800 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2025-11-08 17:21:54 -0800 |
| commit | 206e4bbdaba85062a38b32c16a9937ab42cddb47 (patch) | |
| tree | 3473090eb3ede734095bbc30670e2ccd962e7181 /Hotline | |
| parent | 2112b181aa654fc9d05770d09aa0cd098cd76bc9 (diff) | |
Improve sound effect management and use NSSound on macOS.
Diffstat (limited to 'Hotline')
| -rw-r--r-- | Hotline/Library/SoundEffects.swift | 51 | ||||
| -rw-r--r-- | Hotline/State/HotlineState.swift | 18 |
2 files changed, 30 insertions, 39 deletions
diff --git a/Hotline/Library/SoundEffects.swift b/Hotline/Library/SoundEffects.swift index 93f8b9a..4964b94 100644 --- a/Hotline/Library/SoundEffects.swift +++ b/Hotline/Library/SoundEffects.swift @@ -1,7 +1,7 @@ import Foundation -import AVFAudio +import AppKit -enum SoundEffects: String { +enum SoundEffect: String { case loggedIn = "logged-in" case chatMessage = "chat-message" case transferComplete = "transfer-complete" @@ -10,41 +10,32 @@ enum SoundEffects: String { case newNews = "new-news" case serverMessage = "server-message" case error = "error" + + static var all: [SoundEffect] = [.loggedIn, .chatMessage, .transferComplete, .userLogin, .userLogout, .newNews, .serverMessage, .error] } @Observable -class SoundEffectPlayer: NSObject, AVAudioPlayerDelegate { - static let shared = SoundEffectPlayer() +class SoundEffects { + static let shared = SoundEffects() - private var activeSounds: [AVAudioPlayer] = [] + private var preloadedSounds: [SoundEffect: NSSound] = [:] - func playSoundEffect(_ name: SoundEffects) { - // Load a local sound file - guard let soundFileURL = Bundle.main.url( - forResource: name.rawValue, - withExtension: "aiff" - ) else { - return - } - - DispatchQueue.main.async { [weak self] in - guard let self = self else { - return - } - - if let soundEffect = try? AVAudioPlayer(contentsOf: soundFileURL) { - soundEffect.delegate = self - soundEffect.volume = 0.75 - soundEffect.play() - - self.activeSounds.append(soundEffect) + private init() { + // Preload sound effects + for effect in SoundEffect.all { + if let soundFileURL = Bundle.main.url(forResource: effect.rawValue, withExtension: "aiff"), + let sound = NSSound(contentsOf: soundFileURL, byReference: true) { + sound.volume = 0.75 + self.preloadedSounds[effect] = sound } } } - - func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { - if let i = self.activeSounds.firstIndex(of: player) { - self.activeSounds.remove(at: i) - } + + static func play(_ name: SoundEffect) { + Self.shared.play(name) + } + + func play(_ name: SoundEffect) { + self.preloadedSounds[name]?.play() } } diff --git a/Hotline/State/HotlineState.swift b/Hotline/State/HotlineState.swift index 4b74df7..4e28af8 100644 --- a/Hotline/State/HotlineState.swift +++ b/Hotline/State/HotlineState.swift @@ -334,7 +334,7 @@ class HotlineState: Equatable { print("HotlineState.login(): Status set to loggedIn") if Prefs.shared.playSounds && Prefs.shared.playLoggedInSound { - SoundEffectPlayer.shared.playSoundEffect(.loggedIn) + SoundEffects.play(.loggedIn) } print("HotlineState.login(): Connected to \(self.serverTitle)") @@ -639,7 +639,7 @@ class HotlineState: Equatable { try await client.sendInstantMessage(text, to: userID) if Prefs.shared.playPrivateMessageSound { - SoundEffectPlayer.shared.playSoundEffect(.chatMessage) + SoundEffects.play(.chatMessage) } } @@ -1776,7 +1776,7 @@ class HotlineState: Equatable { private func handleChatMessage(_ text: String) { if Prefs.shared.playSounds && Prefs.shared.playChatSound { - SoundEffectPlayer.shared.playSoundEffect(.chatMessage) + SoundEffects.play(.chatMessage) } let chatMessage = ChatMessage(text: text, type: .message, date: Date()) @@ -1798,14 +1798,14 @@ class HotlineState: Equatable { } if Prefs.shared.playSounds && Prefs.shared.playLeaveSound { - SoundEffectPlayer.shared.playSoundEffect(.userLogout) + SoundEffects.play(.userLogout) } } } private func handleServerMessage(_ message: String) { if Prefs.shared.playSounds && Prefs.shared.playChatSound { - SoundEffectPlayer.shared.playSoundEffect(.serverMessage) + SoundEffects.play(.serverMessage) } print("HotlineState: received server message:\n\(message)") @@ -1820,9 +1820,9 @@ class HotlineState: Equatable { if Prefs.shared.playPrivateMessageSound { if self.unreadInstantMessages[userID] == nil { - SoundEffectPlayer.shared.playSoundEffect(.serverMessage) + SoundEffects.play(.serverMessage) } else { - SoundEffectPlayer.shared.playSoundEffect(.chatMessage) + SoundEffects.play(.chatMessage) } } @@ -1854,7 +1854,7 @@ class HotlineState: Equatable { self.messageBoard.insert(message, at: 0) } - SoundEffectPlayer.shared.playSoundEffect(.newNews) + SoundEffects.play(.newNews) } // MARK: - User Management @@ -1868,7 +1868,7 @@ class HotlineState: Equatable { } else { if !self.users.isEmpty { if Prefs.shared.playSounds && Prefs.shared.playJoinSound { - SoundEffectPlayer.shared.playSoundEffect(.userLogin) + SoundEffects.play(.userLogin) } } |