Skip to content
mskayyaliPublic

About

Local-first, Mac-native text-based audio editor for podcasts: edit the audio by editing its transcript. Transcription, clean-up and speaker detection run on your Mac.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Wave

A text-based audio editor for podcasts, made for the Mac. Edit audio by editing text: delete a word in the transcript and it's cut from the audio. Everything runs on your Mac. There's no cloud, no account and no upload.

Wave's editor

Download

Download Wave 1.2.1 for Mac (DMG). Earlier versions are on the releases page, and there's a website too.

What you need

  • A Mac with Apple Silicon (M1 or later). Intel Macs aren't supported.
  • macOS 13.4 (Ventura) or later.
  • About 2 GB of free space for the speech models, and an internet connection to download them once. After that, Wave works offline.

Nothing else: no account, no FFmpeg, no Python.

Install

  1. Open the DMG and drag Wave into Applications.

  2. Open Wave. The app and installer are signed with Developer ID and notarized by Apple. macOS may ask you to confirm opening an app downloaded from the internet the first time.

    Or, in Terminal:

    xattr -dr com.apple.quarantine /Applications/Wave.app
  3. In Wave, click Set up transcription (or open Settings) and download Whisper (1.6 GB: Whisper Large v3 Turbo and the word aligner), or Parakeet v3 (681 MB). Choose the model under Settings → Transcription model; Wave remembers the choice for new recordings. Parakeet includes word timing, supports English and 24 other European languages, and does not support Arabic. Existing transcripts and edits stay as they are. Two more models are optional:

    • DPDFNet (14 MB): removes background noise and room echo.
    • Speaker detection (115 MB): finds who speaks when.

Updates

Wave updates itself. If you use 1.1.0, download and install the current release manually once: the updater signing key was replaced in 1.2.0. Your projects and models are retained. Updates work automatically from 1.2.0 onward, including the notarized 1.2.1 release. It checks quietly in the background, and when there's a new version, a small dot appears beside the version in the sidebar (and in the editor's top bar). Click it to see what's new, then choose Update and restart or Later. Wave never installs or restarts without asking, and if a transcription or export is running, it waits for it to finish. You can also use Wave → Check for Updates…, or turn automatic checks off in Settings → Updates.

Quick start

  1. Click New project (⌘N) and choose a recording, or drop audio files anywhere on the window. MP3, WAV, M4A, FLAC and more work.
  2. Wave transcribes it on your Mac using the model selected in Settings.
  3. Edit the text:
    • Select words and press ⌫ to cut them from the audio. Press C first to hear the result.
    • Press Space to play. The playing word is highlighted, and clicking a word jumps to it.
    • To fix a misheard word, select it and press ↩.
    • ⌘Z undoes anything. The original audio is never changed.
  4. Use the Tools tab to shorten pauses, clean up the sound, apply an EQ preset or detect speakers.
  5. Use the Export tab to save the edited audio as MP3, AAC, WAV or FLAC, and the transcript as TXT, SRT, WebVTT or JSON.

Keyboard shortcuts

Keys What they do
Space Play or pause
← → Back or forward 5 seconds
⌫ Delete the selection
C Hear the selection as if it were cut
↩ Correct the selected word
⌘Z, ⇧⌘Z Undo, redo
⌘F Find in the transcript
[ ] Select the previous or next word
Z Zoom to the selection; again to go back
? Show every shortcut

Features

  • Local transcription: Whisper writes what was said word for word, including "um" and "uh" in English, so you can cut them. A wav2vec2 aligner then places every word on its exact audio, so cutting a word removes all of it.
  • Text editing: cut words, pauses or any stretch of audio. Cuts are joined with a short crossfade, and playback matches the export exactly.
  • An exact waveform: trim what the text can't, like a breath or the tail of a word. A selection is exactly what you drag, and you can fine-tune its edges to the millisecond (⇧←/→).
  • Word corrections: fix a misheard word. Corrections are marked in green, undo like any edit, and carry into every export.
  • Find: ⌘F finds a phrase, marks every match and cuts them one by one.
  • Pauses: shorten long pauses to a Tight, Natural or Relaxed rhythm, previewed first and undone in one step. You can also add a pause after any word, filled with the room's own quiet.
  • Speech enhancement: remove background noise and room echo (DPDFNet), and set the loudness for podcast delivery (Apple Podcasts, Spotify and YouTube, or broadcast). You can preview 15 seconds against the original first, and switch between the two while playing.
  • EQ presets for the voice, each named for what it fixes: Clearer, Warmer, Less boom, Less boxy, Less nasal, Brighter, Less harsh and Broadcast, at Subtle, Medium or Strong.
  • Speaker detection: finds who speaks when, for up to 8 people. You can rename or merge speakers, select everything one person said, and export the names with the transcript.
  • AI agents: let Claude or ChatGPT edit with you (see below). Their edits appear live and undo like your own.
  • Made for the Mac: a full menu bar, drag and drop, and one status for everything running in the background, with progress on the Dock icon.

Using Wave with Claude or ChatGPT

Wave includes an MCP server, so an AI agent can read your transcripts and make the same edits you can. For example, it can cut filler words and false starts, tighten pauses, fix misspelled names, enhance the audio and export.

  1. In Wave, open Settings → AI agents and turn it on. The page shows the exact setup for your copy of Wave.

  2. Add Wave to your agent app once. For Wave in Applications, the command is /Applications/Wave.app/Contents/MacOS/wave with the argument mcp.

    • Claude Desktop: Settings → Developer → Edit Config, then add the following and restart Claude:

      {
        "mcpServers": {
          "wave": { "command": "/Applications/Wave.app/Contents/MacOS/wave", "args": ["mcp"] }
        }
      }
    • Claude Code:

      claude mcp add --scope user wave -- /Applications/Wave.app/Contents/MacOS/wave mcp
    • Codex, or the ChatGPT desktop app in its Codex and Work modes: Settings → MCP servers → Add server (STDIO, the command above, argument mcp), or run:

      codex mcp add wave -- /Applications/Wave.app/Contents/MacOS/wave mcp
  3. Keep Wave open, and ask, for example: "In my project Episode 12, remove the filler words and false starts, tighten the pauses, and enhance the audio with the Clearer EQ."

Agents can use plan_edit to dry-run word or time cuts through the actual boundary and fade planner, then apply with expected_revision so a concurrent edit cannot silently invalidate the plan. get_transitions exposes resolved source/output times, fades, manual overrides and joins flagged for listening. Time cuts overlapping kept speech require allow_word_trim=true for an intentional exact trim; whole-word edits should use cut_words. Audio edits wait until analysis is ready. Reconnect MCP clients using the updated Wave executable to discover the new tools.

Good to know:

  • Wave must be running with AI agents turned on.
  • Your project opens in Wave when an agent works on it, and you can watch the edits as they're made.
  • ChatGPT in the browser, and the desktop app's plain chat, can't reach apps on your Mac, so they can't use Wave.
  • Agents can't hear the audio. They work from the words, their timing and the pauses, so give the result a listen.

Build from source

You need:

  • A Mac with Apple Silicon and macOS 13.4 or later.
  • Xcode Command Line Tools: xcode-select --install.
  • Rust.
  • bun.
  • CMake, which builds whisper.cpp: brew install cmake.

Then:

git clone https://github.com/mskayyali/wave.git
cd wave
bun install
bun run setup:parakeet # download and verify NVIDIA's small native Mac runtime
bunx tauri dev      # run Wave in development
bunx tauri build    # build Wave.app and the DMG

bunx tauri build writes Wave.app and the DMG to src-tauri/target/release/bundle/. The first build takes several minutes: it compiles whisper.cpp with Metal support and downloads ONNX Runtime.

MP3 export uses LAME, which is prebuilt in src-tauri/vendor/lame/. To rebuild it, run build.sh in that folder.

Publishing a release

Releases are signed, so installed copies of Wave only accept updates that really come from you.

The release script defaults to Developer ID signing and Apple notarization. Configure APPLE_API_KEY, APPLE_API_ISSUER and APPLE_API_KEY_PATH in the environment, or as fields in ~/.tauri/wave-notarization.json outside the repository. The corresponding Developer ID Application identity must be available in the Mac keychain. Nested Parakeet code is signed before Tauri seals the app, and its signing team is verified alongside LAME before publication. WAVE_UNNOTARIZED=1 explicitly selects the earlier Open Anyway installation flow.

  1. Once, make the updater's key. It asks for a password. Keep both safe, and never commit them:

    bunx tauri signer generate -w ~/.tauri/wave-updater.key
  2. Write what's new in a Markdown file, then publish:

    scripts/release.sh 1.2.2 notes.md

The script bumps the version, builds Wave and its signed update, and publishes a GitHub release with the DMG, the update and latest-v2.json, which installed copies from 1.2.0 onward read. Each release also includes the unchanged release-notes/legacy-updater.json as latest.json, keeping 1.1.0 installations from being offered an incompatible update. The first time, it also adds the key's public half to src-tauri/tauri.conf.json. If the key is ever lost, installed copies can't update any more, and everyone has to download the next version by hand once.

How it's put together

Wave is a Tauri 2 app. The interface is React and TypeScript with IBM's Carbon design system (src/), and the audio work is in Rust (src-tauri/src/):

File What it does
projects.rs Projects, audio import, edits and audio export
transcription.rs Transcription with whisper.cpp (whisper-rs, on the GPU)
parakeet.rs Parakeet TDT v3 through bundled NeMo-Speech.cpp, with bounded chunks and original-audio word timings
alignment.rs Word timings by wav2vec2 forced alignment (ONNX Runtime)
src/lib/editPlan.ts, edit_plan.rs One resolved timeline for playback, audio export and subtitles; matching PCM renderers
src/lib/cutBoundaries.ts Text-cut boundaries constrained to gaps around kept words
enhance.rs, dpdfnet.rs, eq.rs, master.rs Noise removal, EQ, and loudness (ITU-R BS.1770-4) with a true-peak limiter
encode.rs, lame.rs MP3, AAC, WAV and FLAC files
speakers.rs Speaker detection
waveform.rs The waveform the editor draws
agent.rs, mcp.rs The MCP server for AI agents
models.rs Model downloads
update.rs Updates: whether this copy can update itself, and the menu item that follows an update (the updater plugin downloads and installs)

Everything is stored in ~/Library/Application Support/com.mskayyali.wave/: the models in models/, and each project in projects/. Edits are kept as a list and only applied to the audio at export, so the original is never changed.

Precise editing and returning to a project

Text selections remove the selected words with protected boundaries. Waveform selections and numeric start/end/duration controls cut the exact audio range on a 1 ms grid; snapping is optional. The transcript and waveform derive removed/partly cut markers from the same resolved audio cuts. Even a 1 ms trim is marked; a word with any audio remaining stays partially cut. Text and subtitle exports retain that word with clipped timing. Restore audio brings back manual trims too, and restoration and boundary drags each undo as one transaction.

Use Text ↗ or the context menu to reveal the same selection in the other editor; F6 switches focus. Tab moves through controls; ⌥↓ / ⌥↑ navigate cuts. Follow controls playback following in both views. Manual scrolling pauses following until it is enabled again. Selection loops run on the audio clock at every playback speed, including across cuts and inserted pauses.

Each project's last playhead, selection, active editor, Flow/Segments view, transcript scroll anchor, waveform time window, Follow setting and panel height are saved locally. Reopening restores them after audio and edits load and stays paused. Transcript or alignment changes invalidate positional selections and scroll anchors. Edit-file writes are ordered and replaced atomically so a late save cannot overwrite a newer one.

Checking audio edits

Run bun test for the timeline, boundary and playback regression tests, and cargo test --lib in src-tauri/ for the native renderer and export tests. bun run build checks the interface and production build. With the local development server running, node tests/browser/run-editor.mjs runs the isolated browser regression fixture (requires Playwright and Chromium; PLAYWRIGHT_MODULE and CHROME_PATH can point to an existing installation; BROWSER_ENGINE=webkit and BROWSER_PATH run the same suite in WebKit). It uses generated audio and a mock project, never user media.

src/lib/editPlan.ts resolves cuts and inserted pauses into source spans, output positions and bounded fades. Both normal and speed-adjusted playback render that plan; audio export receives the same plan, and subtitles use its source-to-output mapping. Renderers must not independently snap boundaries or change overlaps. Linear fades avoid boosting correlated signals, and room-tone loops blend at every wrap. Automatic text cuts protect kept word spans; tightly joined speech is marked Review transition on the waveform and can be auditioned with C.

The playback and native renderer tests share tests/fixtures/edit-plans.json, including stereo, fractional boundaries, short segments and inserted pauses. Listening tests on real speech are still needed when changing boundary scoring or fade defaults: synthetic parity tests establish consistency, not whether a particular speech edit sounds natural.

Credits

Wave runs these models, downloaded in the app:

  • Whisper Large v3 Turbo through whisper.cpp (MIT).
  • Parakeet TDT v3 by NVIDIA (CC BY 4.0), pinned Q8 model, through NeMo-Speech.cpp 0.3.0 (Apache-2.0; bundled third-party notices). The model is downloaded locally and verified against NVIDIA's SHA-256. Parakeet does not report language IDs or calibrated confidence in this runtime; Details shows those as unavailable.
  • wav2vec2 (Apache-2.0).
  • DPDFNet by Ceva (Apache-2.0).
  • Nemotron 3 Diarization by NVIDIA (OpenMDW 1.1).

MP3 export uses LAME 3.100, bundled as a separate library under the LGPL. Its source is at sourceforge.net/projects/lame.

Built by Saleh Kayyali (@mskayyali).

About

Local-first, Mac-native text-based audio editor for podcasts: edit the audio by editing its transcript. Transcription, clean-up and speaker detection run on your Mac.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages