v0.4: persistent config in AppData, voices in LOCALAPPDATA, remove Speak button

This commit is contained in:
2026-08-10 12:32:07 +00:00
parent 9b0dc11ee6
commit fbbb52df90
3 changed files with 113 additions and 20 deletions
+55 -11
View File
@@ -10,8 +10,9 @@ namespace Robovoice.App;
internal sealed partial class MainForm : Form
{
private readonly string _voicesDir = @"C:\data\opencode\robovoice-voices";
private readonly string _voicesDir = AppConfig.VoicesDir;
private readonly string _espeakDataPath;
private readonly AppConfig _config;
private LibPiperTtsEngine? _tts;
private AudioOutput? _audioOutput;
@@ -25,21 +26,40 @@ internal sealed partial class MainForm : Form
{
InitializeComponent();
_espeakDataPath = Path.Combine(AppContext.BaseDirectory, "espeak-ng-data");
_config = AppConfig.Load();
Directory.CreateDirectory(AppConfig.AppDataDir);
Directory.CreateDirectory(_voicesDir);
Load += OnLoad;
FormClosing += OnFormClosing;
}
private async void OnLoad(object? sender, EventArgs e)
{
ActiveControl = txtLog;
PopulateVoices();
PopulateOutputDevices();
_pttKey = Keys.F8;
_pttKey = (Keys)_config.PttKey;
if (_pttKey == Keys.None)
_pttKey = Keys.F8;
txtPttKey.Text = KeyToDisplayString(_pttKey);
if (cmbVoice.Items.Count > 0)
if (!string.IsNullOrEmpty(_config.Voice) && cmbVoice.Items.Contains(_config.Voice))
cmbVoice.SelectedItem = _config.Voice;
else if (cmbVoice.Items.Count > 0)
cmbVoice.SelectedIndex = 0;
AutoSelectCableOutput();
if (!string.IsNullOrEmpty(_config.OutputDevice) && cmbOutput.Items.Contains(_config.OutputDevice))
cmbOutput.SelectedItem = _config.OutputDevice;
else
AutoSelectCableOutput();
trkNoise.Value = _config.NoiseScale;
trkSpeed.Value = _config.LengthScale;
trkNoiseW.Value = _config.NoiseWScale;
OnSliderScroll(null, EventArgs.Empty);
chkMinimizeToTray.Checked = _config.MinimizeToTray;
btnBrowseFile.Click += OnBrowseFile;
btnTestVoice.Click += OnTestVoice;
@@ -57,6 +77,10 @@ internal sealed partial class MainForm : Form
trkSpeed.MouseUp += OnSliderReleased;
trkNoiseW.MouseUp += OnSliderReleased;
chkMinimizeToTray.CheckedChanged += (_, _) => SaveConfig();
Resize += OnResize;
SetupTray();
await InitializeEngineAsync();
@@ -98,6 +122,7 @@ internal sealed partial class MainForm : Form
_captureHook?.Dispose();
_captureHook = null;
SetupHotkey();
SaveConfig();
}
private void CancelCapture()
@@ -334,6 +359,7 @@ internal sealed partial class MainForm : Form
cmbVoice.SelectedIndex = 0;
}
SaveConfig();
_ = InitializeEngineAsync();
}
@@ -344,6 +370,7 @@ internal sealed partial class MainForm : Form
if (cmbVoice.SelectedItem is string name)
{
SaveConfig();
_ = ReinitializeEngineAsync(name);
}
}
@@ -368,6 +395,7 @@ internal sealed partial class MainForm : Form
private void OnSliderReleased(object? sender, MouseEventArgs e)
{
SaveConfig();
if (cmbVoice.SelectedItem is string name && VoiceCatalogue.IsVoiceInstalled(_voicesDir, name))
{
_ = InitializeEngineAsync();
@@ -379,6 +407,7 @@ internal sealed partial class MainForm : Form
if (_orchestrator is not null)
_orchestrator.OutputDeviceName = cmbOutput.SelectedItem as string ?? string.Empty;
Log($"Output device: {_orchestrator?.OutputDeviceName}");
SaveConfig();
}
private void UpdateLineStatus()
@@ -415,6 +444,15 @@ internal sealed partial class MainForm : Form
_trayIcon.DoubleClick += (_, _) => ShowWindow();
}
private void OnResize(object? sender, EventArgs e)
{
if (WindowState == FormWindowState.Minimized && chkMinimizeToTray.Checked)
{
Hide();
WindowState = FormWindowState.Normal;
}
}
private void ShowWindow()
{
Show();
@@ -422,6 +460,18 @@ internal sealed partial class MainForm : Form
Activate();
}
private void SaveConfig()
{
_config.Voice = cmbVoice.SelectedItem as string ?? string.Empty;
_config.PttKey = (int)_pttKey;
_config.OutputDevice = cmbOutput.SelectedItem as string ?? string.Empty;
_config.NoiseScale = trkNoise.Value;
_config.LengthScale = trkSpeed.Value;
_config.NoiseWScale = trkNoiseW.Value;
_config.MinimizeToTray = chkMinimizeToTray.Checked;
_config.Save();
}
private void Log(string message)
{
if (IsDisposed) return;
@@ -438,15 +488,9 @@ internal sealed partial class MainForm : Form
private void OnFormClosing(object? sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing && chkMinimizeToTray.Checked && _trayIcon?.Visible == true)
{
e.Cancel = true;
Hide();
return;
}
_pttHotkey?.Dispose();
_trayIcon!.Visible = false;
_orchestrator?.DisposeAsync().AsTask().Wait();
SaveConfig();
}
}