Import Coucou 0.1.9 (Louis-CFM/coucou@83708fe), Mac app only

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
maksarsanjeev
2026-10-06 19:34:32 +03:00
commit 53b4f60da1
158 changed files with 29442 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
import AVFoundation
import AppKit
/// Preloaded WAV players with near-zero latency.
/// Volume default 0.12 (matches prototype: gain ×6 then vol=0.12).
@MainActor
final class SoundEngine {
static let shared = SoundEngine()
var enabled: Bool = true
var volume: Float = 0.12 {
didSet { players.values.forEach { $0.forEach { $0.volume = volume } } }
}
// Pool of 3 players per sound to allow overlapping playback
private var players: [String: [AVAudioPlayer]] = [:]
private init() {
preload()
}
private func preload() {
let names = ["peek","open","close","hover","blip","slap","annoyed","dizzy","greet",
"work","finish","error","approval","question","approve","gulp","tick",
"send","love","pop","proud","wink","yawn","attach","think","search",
"rate","sleep","greeting"]
for name in names {
guard let url = Bundle.main.url(forResource: name, withExtension: "wav", subdirectory: "sounds") else { continue }
var pool: [AVAudioPlayer] = []
for _ in 0..<3 {
if let p = try? AVAudioPlayer(contentsOf: url) {
p.volume = volume
p.prepareToPlay()
pool.append(p)
}
}
if !pool.isEmpty { players[name] = pool }
}
}
/// Fade out all currently-playing instances of `name` over `duration` seconds,
/// then stop and reset them so they can be reused.
func fadeOut(_ name: String, duration: TimeInterval) {
guard let pool = players[name] else { return }
for player in pool where player.isPlaying {
player.setVolume(0, fadeDuration: duration)
DispatchQueue.main.asyncAfter(deadline: .now() + duration) { [weak player] in
guard let p = player else { return }
p.stop()
p.currentTime = 0
p.volume = self.volume
}
}
}
func play(_ name: String) {
guard enabled && AppState.shared.soundEnabled else { return }
guard let pool = players[name] else { return }
// Find a player that is not currently playing
let player = pool.first { !$0.isPlaying } ?? pool[0]
player.currentTime = 0
player.volume = volume
player.play()
}
}