aboutsummaryrefslogtreecommitdiff
path: root/Hotline
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2025-11-08 17:21:54 -0800
committerDustin Mierau <dustin@mierau.me>2025-11-08 17:21:54 -0800
commit206e4bbdaba85062a38b32c16a9937ab42cddb47 (patch)
tree3473090eb3ede734095bbc30670e2ccd962e7181 /Hotline
parent2112b181aa654fc9d05770d09aa0cd098cd76bc9 (diff)
Improve sound effect management and use NSSound on macOS.
Diffstat (limited to 'Hotline')
-rw-r--r--Hotline/Library/SoundEffects.swift51
-rw-r--r--Hotline/State/HotlineState.swift18
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)
}
}