156 lines
5.5 KiB
Swift
156 lines
5.5 KiB
Swift
//
|
|
// SoundConfiguration.swift
|
|
// AudioPlaybackKit
|
|
//
|
|
// Created by Matt Bruce on 9/8/25.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
/// Configuration model for sound system loaded from JSON
|
|
public struct SoundConfiguration: Codable {
|
|
public let sounds: [Sound]
|
|
public let settings: AudioSettings
|
|
|
|
public init(sounds: [Sound], settings: AudioSettings) {
|
|
self.sounds = sounds
|
|
self.settings = settings
|
|
}
|
|
}
|
|
|
|
/// Simple struct for loading just the sounds array from category JSON files
|
|
public struct SoundsOnly: Codable {
|
|
public let sounds: [Sound]
|
|
|
|
public init(sounds: [Sound]) {
|
|
self.sounds = sounds
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// Audio settings configuration
|
|
public struct AudioSettings: Codable {
|
|
public let defaultVolume: Float
|
|
public let defaultLoopCount: Int
|
|
public let preloadSounds: Bool
|
|
public let preloadStrategy: String // "all", "category", "none"
|
|
public let audioSessionCategory: String
|
|
public let audioSessionMode: String
|
|
public let audioSessionOptions: [String]
|
|
|
|
public init(defaultVolume: Float, defaultLoopCount: Int, preloadSounds: Bool, preloadStrategy: String, audioSessionCategory: String, audioSessionMode: String, audioSessionOptions: [String]) {
|
|
self.defaultVolume = defaultVolume
|
|
self.defaultLoopCount = defaultLoopCount
|
|
self.preloadSounds = preloadSounds
|
|
self.preloadStrategy = preloadStrategy
|
|
self.audioSessionCategory = audioSessionCategory
|
|
self.audioSessionMode = audioSessionMode
|
|
self.audioSessionOptions = audioSessionOptions
|
|
}
|
|
}
|
|
|
|
/// Service for loading and managing sound configuration
|
|
public class SoundConfigurationService {
|
|
public static let shared = SoundConfigurationService()
|
|
|
|
private var configuration: SoundConfiguration?
|
|
|
|
private init() {}
|
|
|
|
|
|
/// Load audio settings from SoundsSettings.json
|
|
private func loadAudioSettings(from bundle: Bundle = .main) -> AudioSettings {
|
|
guard let url = bundle.url(forResource: "SoundsSettings", withExtension: "json") else {
|
|
print("⚠️ Warning: SoundsSettings.json not found, using default settings")
|
|
return AudioSettings(
|
|
defaultVolume: 0.8,
|
|
defaultLoopCount: -1,
|
|
preloadSounds: true,
|
|
preloadStrategy: "category",
|
|
audioSessionCategory: "playback",
|
|
audioSessionMode: "default",
|
|
audioSessionOptions: ["mixWithOthers"]
|
|
)
|
|
}
|
|
|
|
do {
|
|
let data = try Data(contentsOf: url)
|
|
let settings = try JSONDecoder().decode(AudioSettings.self, from: data)
|
|
print("✅ Loaded audio settings from SoundsSettings.json")
|
|
return settings
|
|
} catch {
|
|
print("⚠️ Warning: Error loading audio settings, using defaults: \(error)")
|
|
return AudioSettings(
|
|
defaultVolume: 0.8,
|
|
defaultLoopCount: -1,
|
|
preloadSounds: true,
|
|
preloadStrategy: "category",
|
|
audioSessionCategory: "playback",
|
|
audioSessionMode: "default",
|
|
audioSessionOptions: ["mixWithOthers"]
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Load sound configuration from multiple category-specific JSON files
|
|
public func loadConfigurationFromBundles(from bundle: Bundle = .main) -> SoundConfiguration {
|
|
// Include AlarmSounds bundle for alarm sound preview functionality
|
|
let bundleNames = ["Colored", "Nature", "Mechanical", "Ambient", "AlarmSounds"]
|
|
var allSounds: [Sound] = []
|
|
|
|
for bundleName in bundleNames {
|
|
guard let bundleURL = bundle.url(forResource: bundleName, withExtension: "bundle"),
|
|
let categoryBundle = Bundle(url: bundleURL),
|
|
let url = categoryBundle.url(forResource: "sounds", withExtension: "json") else {
|
|
print("⚠️ Warning: Could not find sounds.json in \(bundleName).bundle")
|
|
continue
|
|
}
|
|
|
|
do {
|
|
let data = try Data(contentsOf: url)
|
|
let soundsOnly = try JSONDecoder().decode(SoundsOnly.self, from: data)
|
|
allSounds.append(contentsOf: soundsOnly.sounds)
|
|
|
|
print("✅ Loaded \(soundsOnly.sounds.count) sounds from \(bundleName).bundle")
|
|
} catch {
|
|
print("⚠️ Warning: Error loading sounds from \(bundleName).bundle: \(error)")
|
|
}
|
|
}
|
|
|
|
// Load settings from separate file
|
|
let settings = loadAudioSettings(from: bundle)
|
|
|
|
let config = SoundConfiguration(sounds: allSounds, settings: settings)
|
|
self.configuration = config
|
|
print("✅ Loaded combined sound configuration with \(allSounds.count) sounds from \(bundleNames.count) bundles")
|
|
return config
|
|
}
|
|
|
|
/// Get current configuration
|
|
public func getConfiguration() -> SoundConfiguration {
|
|
if configuration == nil {
|
|
return loadConfigurationFromBundles()
|
|
}
|
|
return configuration!
|
|
}
|
|
|
|
/// Get all available sounds
|
|
public func getAvailableSounds() -> [Sound] {
|
|
return getConfiguration().sounds
|
|
}
|
|
|
|
/// Get sounds by category
|
|
public func getSoundsByCategory(_ categoryId: String) -> [Sound] {
|
|
return getConfiguration().sounds
|
|
.filter { $0.category == categoryId }
|
|
}
|
|
|
|
|
|
/// Get audio settings
|
|
public func getAudioSettings() -> AudioSettings {
|
|
return getConfiguration().settings
|
|
}
|
|
|
|
}
|