using Foundation; using VoiceCat.Audio; namespace VoiceCat.Mac; internal sealed class MacSettings { private readonly NSUserDefaults values = NSUserDefaults.StandardUserDefaults; internal AudioInputMode InputMode { get; set; } = AudioInputMode.VoiceActivation; internal float VadThreshold { get; set; } = 0.05f; internal float InputGain { get; set; } = 1f; internal float OutputGain { get; set; } = 0.8f; internal bool InputNoiseReduction { get; set; } internal bool StereoMicrophone { get; set; } internal ushort PushToTalkKeyCode { get; set; } = 0x60; internal string? InputDeviceId { get; set; } internal string? OutputDeviceId { get; set; } internal bool AuxiliaryEnabled { get; set; } internal string? AuxiliaryDeviceId { get; set; } internal float AuxiliaryGain { get; set; } = 1f; internal bool EventSounds { get; set; } = true; internal bool SpokenEvents { get; set; } internal float EventVolume { get; set; } = 1f; internal bool SelfTalkSounds { get; set; } internal bool PushToTalkSound { get; set; } internal void Load() { NSString[] keys = [(NSString)"voice.inputMode", (NSString)"voice.vadThreshold", (NSString)"voice.inputGain", (NSString)"voice.outputGain", (NSString)"voice.pttKeyCode", (NSString)"voice.auxGain", (NSString)"feedback.sounds", (NSString)"feedback.volume"]; NSObject[] defaults = [NSNumber.FromInt32((int)AudioInputMode.VoiceActivation), NSNumber.FromFloat(0.05f), NSNumber.FromFloat(1f), NSNumber.FromFloat(0.8f), NSNumber.FromInt32(0x60), NSNumber.FromFloat(1f), NSNumber.FromBoolean(true), NSNumber.FromFloat(1f)]; values.RegisterDefaults(new NSDictionary(keys, defaults)); InputMode = Enum.IsDefined(typeof(AudioInputMode), (int)values.IntForKey("voice.inputMode")) ? (AudioInputMode)(int)values.IntForKey("voice.inputMode") : AudioInputMode.VoiceActivation; VadThreshold = Math.Clamp(values.FloatForKey("voice.vadThreshold"), 0f, 1f); InputGain = Math.Clamp(values.FloatForKey("voice.inputGain"), 0f, 4f); OutputGain = Math.Clamp(values.FloatForKey("voice.outputGain"), 0f, 1f); InputNoiseReduction = values.BoolForKey("voice.inputNoiseReduction"); StereoMicrophone = values.BoolForKey("voice.stereoMic"); PushToTalkKeyCode = checked((ushort)Math.Clamp(values.IntForKey("voice.pttKeyCode"), 0, ushort.MaxValue)); InputDeviceId = EmptyToNull(values.StringForKey("voice.inputDevice")); OutputDeviceId = EmptyToNull(values.StringForKey("voice.outputDevice")); AuxiliaryEnabled = values.BoolForKey("voice.auxEnabled"); AuxiliaryDeviceId = EmptyToNull(values.StringForKey("voice.auxDeviceUID")); AuxiliaryGain = Math.Clamp(values.FloatForKey("voice.auxGain"), 0f, 4f); EventSounds = values.BoolForKey("feedback.sounds"); SpokenEvents = values.BoolForKey("feedback.speech"); EventVolume = Math.Clamp(values.FloatForKey("feedback.volume"), 0f, 1f); SelfTalkSounds = values.BoolForKey("feedback.selfTalk"); PushToTalkSound = values.BoolForKey("feedback.ptt"); } internal void Save() { values.SetInt((int)InputMode, "voice.inputMode"); values.SetFloat(VadThreshold, "voice.vadThreshold"); values.SetFloat(InputGain, "voice.inputGain"); values.SetFloat(OutputGain, "voice.outputGain"); values.SetBool(InputNoiseReduction, "voice.inputNoiseReduction"); values.SetBool(StereoMicrophone, "voice.stereoMic"); values.SetInt(PushToTalkKeyCode, "voice.pttKeyCode"); Set("voice.inputDevice", InputDeviceId); Set("voice.outputDevice", OutputDeviceId); values.SetBool(AuxiliaryEnabled, "voice.auxEnabled"); Set("voice.auxDeviceUID", AuxiliaryDeviceId); values.SetFloat(AuxiliaryGain, "voice.auxGain"); values.SetBool(EventSounds, "feedback.sounds"); values.SetBool(SpokenEvents, "feedback.speech"); values.SetFloat(EventVolume, "feedback.volume"); values.SetBool(SelfTalkSounds, "feedback.selfTalk"); values.SetBool(PushToTalkSound, "feedback.ptt"); values.Synchronize(); } private void Set(string key, string? value) { if (value is null) values.RemoveObject(key); else values.SetString(value, key); } private static string? EmptyToNull(string? value) => string.IsNullOrWhiteSpace(value) ? null : value; }