// Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later package config import "math" // RoundSpeechValues keeps speech controls and persisted voices at one decimal // place without changing the caller's values or turning inheritance into values. func RoundSpeechValues(settings Settings) Settings { for _, voice := range []*Voice{&settings.DefaultVoice, &settings.UppercaseVoice, &settings.HyperlinkVoice, &settings.SystemVoice, &settings.EchoVoice} { for _, field := range []**float64{&voice.Rate, &voice.AveragePitch, &voice.Gain} { if *field != nil { value := math.Round(**field*10) / 10 *field = &value } } } return settings } // EffectiveVoice resolves a sparse voice over Default. Uppercase retains the // established automatic pitch unless overridden or capital pitch is disabled. func EffectiveVoice(settings Settings, kind string) Voice { voice := cloneVoice(settings.DefaultVoice) var override Voice switch kind { case "uppercase": pitch := 7.0 if voice.AveragePitch != nil { pitch = min(9, max(pitch, *voice.AveragePitch+2)) } if settings.RaisePitchForCapitals { voice.AveragePitch = &pitch } override = settings.UppercaseVoice if !settings.RaisePitchForCapitals { override.AveragePitch = nil } case "hyperlink": override = settings.HyperlinkVoice case "system": override = settings.SystemVoice } mergeVoice(&voice, cloneVoice(override)) return voice }