Privacy-first meeting transcriber and dictation tool for Linux. Records microphone and system audio, transcribes locally with Whisper, stores results in SQLite. No cloud, no internet — your audio never leaves your machine.
Two modes: Record meetings with dual audio capture (mic + system), or Dictate with real-time speech-to-text that shows words as you speak.
| Recorder | Recording in progress |
|---|---|
| Pending recordings | Finalizing transcription |
|---|---|
| History | Summary |
|---|---|
pw-record and wpctl (included with PipeWire)# Ubuntu/Debian
sudo apt install -y libwebkit2gtk-4.1-dev libgtk-3-dev libasound2-dev libpulse-dev \
build-essential libssl-dev libayatana-appindicator3-dev librsvg2-dev pipewire
Download the latest .deb from GitHub Releases and install:
sudo apt install ./martin_0.1.0_amd64.deb
On first use, the app automatically downloads the Whisper model (~466MB). Internet required only for this one-time download.
git clone https://github.com/vagnerzampieri/martin.git
cd martin
npm install
cargo install tauri-cli --version "^2"
cargo tauri build
The binary will be in src-tauri/target/release/martin.
You can record multiple times before transcribing — each recording is tracked separately. Close and reopen the app; your pending recordings are still there.
Speak these phrases mid-dictation to insert punctuation or formatting.
Matching is case-insensitive and accent-insensitive — novo paragrafo
works the same as novo parágrafo, and Whisper dropping a diacritic
does not break the command.
| Say (PT) | Produces |
|---|---|
novo parágrafo or ponto parágrafo |
new paragraph (\n\n) |
nova linha |
newline (\n) |
ponto final |
. |
vírgula |
, |
ponto de interrogação |
? |
ponto de exclamação |
! |
abre aspas |
" (opening) |
fecha aspas |
" (closing) |
The dictation also reacts to silence:
Records two audio sources simultaneously:
pw-record targeting the default PipeWire sinkWhen you stop recording, both WAV files are mixed into a single file. If PipeWire is not available or the system audio is corrupt, martin falls back to microphone-only recording. The mixed file is saved as a pending recording and can be transcribed later.
Captures microphone audio via cpal and transcribes in real time:
dictation://level) and session state (dictation://state, one of listening/processing/paused) for UI feedback\n\n) before the next segmentStart Dictation and updated every ~5s during the session; on Stop Dictation the same row is finalized| Model | Size | Quality | Speed |
|---|---|---|---|
| tiny | 75MB | Usable | Fast |
| base | 142MB | Good | Fast |
| small | 466MB | Very good | Moderate |
| medium | 1.5GB | Excellent | Slow |
Download with: ./scripts/download-model.sh <model>
cargo tauri dev # Full app dev mode with hot reload
cargo test # Run Rust tests
npm run check # Svelte/TypeScript type checking
cargo fmt # Format Rust code
cargo clippy # Lint Rust code
src-tauri/src/
├── lib.rs # Tauri commands, app state
├── audio/
│ ├── capture.rs # Mic (cpal) + system audio (pw-record)
│ ├── mix.rs # WAV mixing (mic + system → single file)
│ └── wav_writer.rs # Thread-safe WAV writer (used by recorder and dictation)
├── db/
│ └── store.rs # SQLite CRUD for transcriptions + pending recordings
├── dictation.rs # Real-time mic capture + transcription loop + level/state emitter
├── model.rs # Auto-download Whisper model with progress events
├── postprocess.rs # Pure text normalization: voice commands, spacing, capitalization
├── summarize.rs # Claude CLI integration for AI summaries
├── vad.rs # Pure RMS-based silence detection helpers
└── transcribe/
├── whisper.rs # Whisper transcription + WAV loading + resampling
└── job.rs # Finalize worker + cancel/progress orchestration
src/
├── lib/
│ ├── i18n.js # Locale detection + translations (pt/en)
│ ├── format.js # Shared date/duration formatting
│ ├── appBusy.js # Cross-tab "app busy" store
│ ├── Recorder.svelte # Recording controls + pending recordings list
│ ├── Dictation.svelte # Real-time dictation with state/level/provisional UI
│ ├── VuMeter.svelte # Audio-level meter component
│ ├── FinalizingProgress.svelte # Progress overlay for finalize phase
│ ├── ModelDownload.svelte # Model download progress overlay
│ ├── History.svelte # Transcription list
│ └── TranscriptionView.svelte # View + copy + summarize
└── routes/
└── +page.svelte # Main page (three tabs: Record / Dictation / History)
GPLv3