diff --git a/src/app/features/settings/general/General.tsx b/src/app/features/settings/general/General.tsx
index 624fdf17f..ca2242204 100644
--- a/src/app/features/settings/general/General.tsx
+++ b/src/app/features/settings/general/General.tsx
@@ -2037,7 +2037,7 @@ export function Calls() {
Model
value={callDenoiseModel}
@@ -2066,7 +2066,7 @@ export function Calls() {
[
{ label: 'CPU (one core)', value: selectedDenoiseModel.cpuUsage },
{ label: 'Voice quality', value: selectedDenoiseModel.voiceQuality },
- { label: 'Transients', value: selectedDenoiseModel.transients },
+ { label: 'Typing & clicks', value: selectedDenoiseModel.transients },
{ label: 'Download', value: selectedDenoiseModel.binarySize },
] as const
).map((stat) => (
@@ -2113,7 +2113,7 @@ export function Calls() {
- Transients
+ Typing & clicks
diff --git a/src/app/state/settings.ts b/src/app/state/settings.ts
index 6f6631140..b512d5725 100644
--- a/src/app/state/settings.ts
+++ b/src/app/state/settings.ts
@@ -377,9 +377,11 @@ const defaultSettings: Settings = {
cameraOnJoin: false,
// Tier default stays browser-native (known-good; best-perceived in testing so
- // far). If a user opts into the ML tier, default to the highest-quality model.
+ // far). If a user opts into the ML tier, default to DTLN: in our measurements
+ // it keeps voices the most natural, removes fans and typing well, and costs a
+ // third of DeepFilterNet's CPU.
callNoiseSuppression: 'browser',
- callDenoiseModel: 'deepfilternet',
+ callDenoiseModel: 'dtln',
// "Series suppression" (stack the browser's native NS before the ML model) is
// off by default — best practice is a single NS stage; it's an opt-in test aid.
callDenoiseNativeNS: false,
diff --git a/src/app/utils/lotusDenoiseUtils.test.ts b/src/app/utils/lotusDenoiseUtils.test.ts
index 201ab2947..472d7e72f 100644
--- a/src/app/utils/lotusDenoiseUtils.test.ts
+++ b/src/app/utils/lotusDenoiseUtils.test.ts
@@ -5,10 +5,10 @@ import { DENOISE_MODELS, ML_DENOISE_REQUIREMENTS, isMLDenoiseSupported } from '.
// ── Model catalog (data integrity) ──────────────────────────────────────────
-test('DENOISE_MODELS lists the four models ordered best-quality (highest CPU) first', () => {
+test('DENOISE_MODELS lists the four models most-recommended first', () => {
assert.deepEqual(
DENOISE_MODELS.map((m) => m.id),
- ['deepfilternet', 'dtln', 'rnnoise', 'speex'],
+ ['dtln', 'deepfilternet', 'rnnoise', 'speex'],
);
});
diff --git a/src/app/utils/lotusDenoiseUtils.ts b/src/app/utils/lotusDenoiseUtils.ts
index 0f3d5327e..3f1d9a430 100644
--- a/src/app/utils/lotusDenoiseUtils.ts
+++ b/src/app/utils/lotusDenoiseUtils.ts
@@ -1,8 +1,8 @@
/**
* Detection utilities + model catalog for Lotus ML noise suppression
- * (DeepFilterNet 3 / DTLN / RNNoise / Speex). The catalog is ordered by
- * quality (and, correspondingly, CPU cost) — highest first — and drives the
- * order of the model dropdown in settings.
+ * (DTLN / DeepFilterNet 3 / RNNoise / Speex). The catalog is ordered by
+ * recommendation — most recommended first — and drives the order of the model
+ * dropdown in settings.
*/
import { DenoiseModelId } from '../state/settings';
@@ -10,6 +10,9 @@ import { DenoiseModelId } from '../state/settings';
// CPU = share of ONE core while in a call, measured with each model running
// exactly as Lotus Call runs it (Ryzen 7 PRO 4750GE, Chromium); download = bytes
// actually fetched on first use. Re-measure when a model or its settings change.
+// Ratings come from scoring each model against the clean voice (PESQ/STOI) on
+// real speech mixed with fan, keyboard, street and babble noise at SNR 5 and
+// 15 dB; `transients` is how well it removes typing and clicks.
export type DenoiseModel = {
id: DenoiseModelId;
name: string;
@@ -20,25 +23,25 @@ export type DenoiseModel = {
voiceQuality: 'Moderate' | 'High' | 'Very High';
};
-// Ordered best-quality (highest CPU) first — this is the dropdown order.
+// Ordered most-recommended first — this is the dropdown order.
export const DENOISE_MODELS: DenoiseModel[] = [
{
- id: 'deepfilternet',
- name: 'DeepFilterNet 3 (beta)',
+ id: 'dtln',
+ name: 'DTLN (recommended)',
description:
- 'Studio-grade deep-learning model (48 kHz fullband, ONNX). Best quality; highest CPU and a larger one-time download.',
- cpuUsage: '~30%',
- binarySize: '~18 MB',
+ 'Keeps voices the most natural of the four. Removes fans and typing well, but not traffic or people talking in the background.',
+ cpuUsage: '~9%',
+ binarySize: '~20 MB',
transients: 'Excellent',
voiceQuality: 'Very High',
},
{
- id: 'dtln',
- name: 'DTLN (beta)',
+ id: 'deepfilternet',
+ name: 'DeepFilterNet 3 (strongest)',
description:
- 'Dual-signal deep-learning model (16 kHz). Strong on transient noise; moderate CPU.',
- cpuUsage: '~9%',
- binarySize: '~20 MB',
+ 'Removes the most noise, including loud typing and traffic, but voices can sound slightly muffled. Uses about three times the CPU of DTLN.',
+ cpuUsage: '~30%',
+ binarySize: '~18 MB',
transients: 'Excellent',
voiceQuality: 'High',
},
@@ -46,17 +49,17 @@ export const DENOISE_MODELS: DenoiseModel[] = [
id: 'rnnoise',
name: 'RNNoise',
description:
- 'Lightweight hybrid model (48 kHz). Very low CPU; good for steady noise like fans, but can sound processed at full strength.',
+ 'Very light. Handles steady noise like fans and traffic; does little for typing and can sound slightly processed.',
cpuUsage: '~3%',
binarySize: '< 1 MB',
- transients: 'Good',
+ transients: 'Poor',
voiceQuality: 'Moderate',
},
{
id: 'speex',
- name: 'Speex (Legacy)',
+ name: 'Speex (legacy)',
description:
- 'Classic DSP noise suppressor. Minimal CPU, gentlest on voice; weakest suppression.',
+ 'Classic suppressor kept for very slow computers. Barely reduces noise in our tests; prefer any other option.',
cpuUsage: '~2%',
binarySize: '< 1 MB',
transients: 'Poor',