|
3 | 3 | Every agent working on this repository MUST append a dated entry describing |
4 | 4 | their changes after finishing work. |
5 | 5 |
|
| 6 | +## 2026-09-03 — Searchable Voice picker replaces the gender + voice selects |
| 7 | + |
| 8 | +- **Removed the Voice gender (Female/Male) Select and the gender-filtered Voice |
| 9 | + Select** from the Settings → Voice section. `ttsVoiceGender` was dropped from |
| 10 | + `AppPreferences` (`packages/shared/index.ts`) and from |
| 11 | + `src/main/ipc/preferences.ts` (default, `loadPreferences`, and |
| 12 | + `preferences:set` all updated); the `selectedGender`/`onSelectVoiceGender` |
| 13 | + props were removed from `App.tsx`, `SettingsScreen.tsx`, and `TtsPanel.tsx`. |
| 14 | +- **Added a searchable voice picker** (`src/renderer/components/VoicePicker.tsx`, |
| 15 | + built on new shadcn `ui/popover.tsx` + `ui/command.tsx` primitives pulled from |
| 16 | + `@radix-ui/react-popover` and `cmdk`). It lists **all** voices in two groups — |
| 17 | + **Azure voices** (22) and **macOS system voices** (184, dev) — with |
| 18 | + type-to-search filtering by name **and** id. `TtsPanel.tsx` now renders just |
| 19 | + the Voice label + `VoicePicker` + Test Voice. |
| 20 | +- **Verified via CDP**: Settings → Voice shows one Voice combobox (no "Voice |
| 21 | + gender"); opening it shows Azure voices + macOS system voices; searching |
| 22 | + "prabhat" returns only `Prabhat (IN)` and "alice" matches the Alice system |
| 23 | + voice; selecting updates the trigger and persists `ttsVoiceId` (e.g. |
| 24 | + `en-IN-NeerjaNeural`). Test Voice and Start Meeting still behave correctly. |
| 25 | +- **Validation**: type-check clean; tests 80/80; build OK; ESLint 0 errors |
| 26 | + (removed the `cmdk-input-wrapper` attribute to satisfy `react/no-unknown- |
| 27 | + property`); Prettier clean. |
| 28 | +- Added deps: `cmdk@^1.1.1`, `@radix-ui/react-popover@^1.1.23`. |
| 29 | + |
| 30 | +## 2026-09-03 — Make the Voice gender filter actually visible (Female/Male splits the list) |
| 31 | + |
| 32 | +- `TtsPanel` no longer mixes macOS system voices (gender `unknown`) into the |
| 33 | + gender-filtered Azure list. **Female → only female Azure voices; Male → only |
| 34 | + male Azure voices.** The only macOS voice shown is a currently persisted |
| 35 | + system selection, kept so it is not lost. |
| 36 | +- Verified via CDP: with gender Male the Voice dropdown lists exactly Guy, |
| 37 | + Christopher, Eric, Roger, Steffan, Tony, Ryan, Thomas, William, Prabhat (IN), |
| 38 | + Liam (plus any retained macOS selection). Female uses the identical code |
| 39 | + branch. |
| 40 | +- Validation: type-check, tests 80/80, build OK, ESLint 0 errors, Prettier |
| 41 | + clean. |
| 42 | + |
| 43 | +## 2026-09-03 — Fix: silent Test Voice + "TTS is already running" on Start Meeting |
| 44 | + |
| 45 | +Follow-up bug fix to the voice-selection feature. |
| 46 | + |
| 47 | +- **No audio on Test Voice**: `AudioOutputManager.writeAudio()` silently drops |
| 48 | + audio when the audio output manager is inactive, and `tts:test` never started |
| 49 | + it. The handler now starts `audioOutput` (if not active) before speaking the |
| 50 | + test phrase, so the selected voice is actually audible. Also, non-Azure/system |
| 51 | + voice ids route to the `say` provider (never Azure). |
| 52 | +- **"TTS is already running" on Start Meeting**: `tts:test` used the shared |
| 53 | + singleton `ttsManager` and left it active, so a later session start returned |
| 54 | + "TTS is already running." `tts:test` now uses an **independent `TtsManager`** |
| 55 | + that starts, speaks the test phrase, then self-terminates (`tts:spoken` → |
| 56 | + `setImmediate` stop) and stops the audio output it started, emitting |
| 57 | + `tts:stopped` so the renderer returns to Off. The shared session manager is |
| 58 | + untouched by a test, so Start Meeting works without the error. |
| 59 | +- **Gender filter retained**: Filters the Azure voice list by documented Azure |
| 60 | + gender; dev macOS system voices are appended regardless. Verified via CDP: |
| 61 | + Settings → Voice → gender Male → select voice → Test Voice shows the text with |
| 62 | + provider "Say", badge Active, then auto-returns to Off; Start Meeting |
| 63 | + completes with no "TTS is already running" error. |
| 64 | +- **Validation**: type-check, tests 80/80, build OK, ESLint 0 errors, Prettier |
| 65 | + clean. |
| 66 | + |
| 67 | +## 2026-09-03 — Fix: "Speech playback failed" when selecting/testing a voice |
| 68 | + |
| 69 | +Follow-up bug fix to the voice-selection feature. |
| 70 | + |
| 71 | +- **Root cause**: `createAzureTtsProvider` passed the selected voice id to the |
| 72 | + Azure SDK unconditionally. A macOS `say` voice id (dev-only, selectable only |
| 73 | + when a system voice is picked) is not an Azure voice — Azure rejected it → |
| 74 | + `tts:error` → "Speech playback failed". Selecting an Azure voice without |
| 75 | + `AZURE_SPEECH_KEY`/`AZURE_SPEECH_REGION` also threw immediately. |
| 76 | +- **Fix 1 — voice-aware provider routing**: `provider.ts` |
| 77 | + `createTtsProvider(voiceId?)` routes any non-Azure voice id to the `say` |
| 78 | + provider via new `voiceIsAzure()` (`voices.ts`), so a macOS system voice is |
| 79 | + always synthesized locally and never reaches the Azure SDK. Dev-only; |
| 80 | + production still exposes Azure voices only, so the production Azure path is |
| 81 | + unchanged. |
| 82 | +- **Fix 2 — system voices selectable in dev**: `TtsPanel` lists macOS system |
| 83 | + voices (marked "(macOS)", gender `unknown`) in the Voice dropdown in dev, so |
| 84 | + users can test tones fully offline with `say` and no Azure keys. Azure voices |
| 85 | + still need the Azure credential to synthesize. |
| 86 | +- **Tests**: 2 new `voiceIsAzure` tests; suite 80 passing (was 78). |
| 87 | +- **Validation**: type-check, tests 80/80, build OK, ESLint 0 errors, Prettier |
| 88 | + clean. CDP-verified: selecting a macOS voice + Test Voice completes with no |
| 89 | + error toast and no console errors. |
| 90 | + |
| 91 | +## 2026-09-03 — TTS voice selection: gender + voice dropdowns, Test Voice, dev system voices |
| 92 | + |
| 93 | +Voice selection feature for Settings → Voice (no commit/push). |
| 94 | + |
| 95 | +- **Shared types** (`packages/shared/index.ts`): `VoiceGender` |
| 96 | + (`female | male | unknown`), `TtsVoiceSource` (`azure | system`), `TtsVoice`, |
| 97 | + `ListVoicesResult`; `AppPreferences` gains `ttsVoiceGender` (default |
| 98 | + `female`) and `ttsVoiceId` (default `null`); `ElectronAPI` gains |
| 99 | + `getTtsVoices()` and `testTtsVoice()`. |
| 100 | +- **Voice catalog/enumeration** (`src/main/services/tts/voices.ts`): |
| 101 | + curated `AZURE_VOICES` (22 real Azure Neural English voices with documented |
| 102 | + gender, default `en-US-JennyNeural`); `parseSayVoices()` for `say -v '\?'` |
| 103 | + (system voice gender is `unknown` — macOS exposes no gender metadata, so |
| 104 | + system voices are excluded from the Female/Male filter, documented |
| 105 | + limitation); `listVoices(development)` + `normalizeSelectedVoiceId()` |
| 106 | + (production restricted to curated Azure ids; dev passes through). macOS |
| 107 | + system voices exposed only when `!app.isPackaged` — Azure-only in packaged |
| 108 | + builds. |
| 109 | +- **Provider voice threading**: `createTtsProvider(voiceId?)` → Azure |
| 110 | + (`voiceId` beats `AZURE_TTS_VOICE`, fallback `en-US-JennyNeural`) and `say` |
| 111 | + (`-v <voice>`, default `Samantha`); `TtsManager.start(..., voiceId?)`. |
| 112 | +- **IPC** (`src/main/ipc/tts.ts`): `tts:start` resolves the persisted voice; |
| 113 | + new `tts:list-voices` and `tts:test` (stops active TTS, restarts with the |
| 114 | + selected voice, then feeds a fixed test sentence through the existing |
| 115 | + `ttsManager.onTranslationText(...)` pipeline — no parallel TTS path). |
| 116 | + `resolveTtsVoiceId()` feeds the SessionManager via an injected resolver |
| 117 | + (`setTtsVoiceIdResolver`), keeping the session service electron-free and |
| 118 | + unit-testable. |
| 119 | +- **Preferences** (`src/main/ipc/preferences.ts`): exports `loadPreferences`, |
| 120 | + persists `ttsVoiceGender`/`ttsVoiceId` so a selection survives restart. |
| 121 | +- **UI** (`TtsPanel.tsx`, `App.tsx`, `SettingsScreen.tsx`, new |
| 122 | + `useTtsVoices.ts`): Voice gender Select (Female/Male) + Voice Select filtered |
| 123 | + by gender + dev-only "system voices available in dev" label + **Test Voice** |
| 124 | + button. |
| 125 | +- **Tests** (`tests/voices.test.ts`): 10 new tests; suite 78 passing (was 68). |
| 126 | +- **Validation**: type-check clean, tests 78/78, build OK, ESLint 0 errors, |
| 127 | + Prettier clean; CDP-smoke at 480px (gender + voice dropdowns populate, male |
| 128 | + filter shows male Azure voices, `getTtsVoices` returns 206 voices in dev, |
| 129 | + no horizontal overflow, correct theme). |
| 130 | + |
6 | 131 | ## [1.0.0] - 2026-08-28 |
7 | 132 |
|
8 | 133 | First public open-source release of the Urdu → English Voice Interpreter for |
|
0 commit comments