Build Krisp

KINDAreplaces $16/mosaves $192/yrback to the verdict

0%0 of 20 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A virtual microphone that appears in every application's input list, pulls from your real microphone, runs a noise suppression model in the audio callback without ever missing a deadline, and offers a lower latency model for live calls and a heavier one for recordings.

estimated effort multi-daythe files for this build are in the project pack

LanguageSwift for the application, C or Rust for the audio pathVirtual deviceA Core Audio server plug-inLow latency modelRNNoise, BSD licensed, roughly 10 milliseconds and one coreHigh quality modelDeepFilterNet, roughly 40 milliseconds and more computeBufferingA lock-free ring buffer between capture and processing

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree if you own one

    Why The virtual device is a Core Audio server plug-in, which is a macOS concept. The equivalent on other platforms is a different project.

    Get it Apple menu, then About This Mac.

    Verify About This Mac reports macOS 13 or higher

  2. installfree

    Why Builds the application and the plug-in, and provides Instruments for the timing work in Phase 2.

    Get it Mac App Store or developer.apple.com/xcode. open ↗

    Verify xcodebuild -version prints 16 or higher

  3. decidefree

    Why An audio callback that allocates or blocks produces clicks the user hears and you cannot reproduce. This is the one part of the build where the usual habits are actively wrong.

    Get it Read about real-time safety before Phase 2. The rule is short: no allocation, no locks, no system calls, no unbounded work.

    Verify You can state why a mutex in the audio callback is a bug rather than a risk

  4. have readyfree, but check each licence for redistribution

    Why These are the two models the profiles use. Their latency and compute difference is the product decision in Phase 3.

    Get it Build RNNoise from its repository, which is small and BSD licensed. DeepFilterNet ships a real-time capable build; check its current licence before bundling. open ↗

    Verify Both process a test file and their added latency is measured

  5. have readyfree

    Why Steady fan noise is where every model succeeds. The differences appear on background speech, sudden clatter and reverberation.

    Get it Record them yourself: a fan, a café, a keyboard and a room with hard walls. Keep them as fixtures.

    Verify All four are saved with their noise floor measured

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- This is a real-time audio path, so the state that matters is timing rather than tables.
- device · the published virtual input, its sample rate, its buffer size and its channel count
- profiles(id, name, model, expected_latency_ms, cpu_budget_pct) · one for calls, one for recordings
- stats · rolling callback duration, deadline misses, dropouts, all visible in the interface
- The deadline is the whole design: at a 48 kHz sample rate with a 256 frame buffer you have roughly 5.3 milliseconds to return, every time, without exception.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
DEVICE_SAMPLE_RATErequired48000The published device's sample rate. Applications will resample if they need something else.
DEVICE_BUFFER_FRAMESrequired256Frames per callback. This sets the deadline: 256 frames at 48 kHz is roughly 5.3 milliseconds.
DEFAULT_PROFILErequiredcallsWhich profile is active by default. Calls means the lighter, lower latency model.
DEADLINE_MISS_THRESHOLDrequired5Misses per minute before the application falls back to the lighter model and says so.
OFFLINE_OUTPUT_DIRrequired~/Music/DenoisedWhere offline processed files are written. Never the source directory.

The build, in order

  1. A virtual device that appears in other applications

    Your device shows up in the input list of an application you did not write, and passes audio through unchanged.

    1. A minimal Core Audio server plug-in publishing one input device with a fixed sample rate and channel count. Install it and restart the audio daemon to load it.

      Files plugin/

      terminal
      sudo killall coreaudiod
    2. Real microphone in, virtual device out, no processing. Verify bit-for-bit where you can.

      Files plugin/passthrough.c

    3. A conferencing application and a recorder. Your own test harness will not reveal the sample rate and buffer size assumptions real applications make.

    done when · tick each as it passes
    watch out
    • A server plug-in runs inside a system audio daemon rather than in your application, so a crash in it takes down audio for the whole machine and a debugger cannot attach the way you expect. Keep the plug-in minimal and put every piece of logic you can into your own process, communicating over a shared buffer.
  2. Processing without missing a deadline

    Noise suppression runs in the audio path and the callback always returns in time.

    1. Every buffer allocated at start-up, a lock-free ring buffer between threads, and no system calls in the callback.

      Files audio/ring.c

    2. It expects a specific frame size, so buffer to that size rather than assuming the host's buffer matches.

      Files audio/denoise.c

    3. Duration and deadline misses, aggregated off the audio thread and shown in the interface.

      Files audio/stats.c

    done when · tick each as it passes
    watch out
    • Allocating memory, taking a lock or logging inside the audio callback will eventually block for longer than the deadline, and the result is a click that the user hears and you cannot reproduce. Preallocate everything, use a lock-free ring buffer, and move logging out to another thread.
  3. Two models, two purposes

    You can choose clean audio or low latency, and the interface tells you the cost.

    1. Same buffer contract, different implementation. Switching is swapping the processor, not rebuilding the path.

      Files audio/models/

    2. Round trip through the device, measured rather than quoted. Hardware varies enough that the paper figure is not your figure.

      Files audio/latency.c

    3. Calls and recordings, with the measured numbers shown underneath. Not good and better.

      Files ui/Profiles.swift

    done when · tick each as it passes
    watch out
    • Roughly 40 milliseconds of added latency is not noticeable when you listen back to a recording and is very noticeable in a conversation, where it sits on top of network delay and makes people talk over each other. Label the profiles by purpose rather than by quality, so the choice is obvious.
  4. Recording mode, where latency does not matter

    Files get the best available quality because nothing is waiting on them.

    1. No deadline, full lookahead, best model. This is a different code path on purpose.

      Files offline/process.c

    2. Write a new file alongside. Checksum the source before and after as a test.

      Files offline/process.c

    3. A noise floor measurement from a silent passage, so the improvement is a number rather than an impression.

      Files offline/report.c

    done when · tick each as it passes
    watch out
    • Reusing the real-time path for files throws away the one advantage offline processing has, which is that it can look ahead. Run the file path without the deadline and without the streaming constraints, and it will beat the live path on the same recording.
  5. Behaving well on a real machine

    It survives the things that actually happen: devices changing, sleep, and processor pressure.

    1. Subscribe to Core Audio device notifications and reconfigure the path. Test by unplugging things during a stream.

      Files audio/devices.c

    2. Tear down and rebuild the path around sleep rather than assuming it survives.

      Files audio/lifecycle.c

    3. If deadline misses rise, switch to the lighter model and tell the user. A dropout is worse than a quality reduction.

      Files audio/adaptive.c

    done when · tick each as it passes
    watch out
    • Audio device configuration changes at the worst moments: someone plugs in headphones mid-call. If the plug-in does not handle the change it either produces silence or crashes the audio daemon, and the user's call ends. Subscribe to device change notifications and reconfigure rather than assuming a stable configuration.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more audio & video.