Case study · 2026

noise.

On-device video editor

You work on top of the raw clip: the original is never touched and the clean video is only born on export.

Plataforma
iPhone · iPad
iOS mínimo
26+
Dependencias
0
Correctores
5

Context

noise is a native iOS/iPadOS video editor that automatically cleans up talking videos (reels, vlogs, tutorials, talking-heads). Instead of cutting by hand, you switch on a set of «correctors» that detect and remove what's redundant in the audio —silences, long pauses, fillers, repetitions and stutters— and it also generates automatic subtitles burned into the video.

It's a tool to speed up the first cleanup pass —the most mechanical and tedious one— before the footage goes to final editing. It doesn't replace your editing suite: it takes the boring work off it.

All processing happens on-device: the audio never leaves your phone. Privacy as a feature, not a promise.

The challenge

The biggest architectural challenge: five different correctors must combine into ONE result that feeds both the preview (AVPlayer) and the export (AVAssetExportSession). If preview and export diverge, «what you see» stops being «what you save». On top of that: detecting silences without libraries (reading PCM by hand), transcribing on-device with the new iOS 26 API (no 1-minute limit like the old SFSpeechRecognizer) and mapping two timelines —source and composition— because cuts reorder the time of everything anchored to it.

The solution

A single source of truth for cuts: every corrector contributes the ranges it wants removed and one method (computeCuts) merges them and derives the complement → the ranges to keep. That same list feeds both preview and exporter. Silence detection runs on energy (RMS→dB over 20 ms windows) with no ML or third parties, and «long pauses» reuses the same detector with different parameters: an entire corrector for free.

/// Único sitio donde se decide qué se corta. Cada corrector activo aporta
/// tramos; se unen y se deriva el complemento (lo que se conserva).
/// Preview y export consumen exactamente la misma lista → WYSIWYG.
private func computeCuts() async {
    var cuts: [ClosedRange<Double>] = []
    if removeSilences    { cuts += await silenceCuts(url: sourceURL) }
    if removeLongPauses  { cuts += await longPauseCuts(url: sourceURL) }
    if removeFillers     { cuts += fillerCuts() }
    if removeRepetitions { cuts += repetitionCuts() }

    removedSegments = Self.merge(cuts)                  // une solapados
    keepRanges = Self.complement(of: removedSegments,   // lo que se conserva
                                 within: 0...duration)
}

// El mismo keepRanges viaja a preview y export como CMTimeRange:
private var keepCMRanges: [CMTimeRange]? {
    keepRanges.map { CMTimeRange(
        start: CMTime(seconds: $0.lowerBound, preferredTimescale: 600),
        end:   CMTime(seconds: $0.upperBound, preferredTimescale: 600)) }
}
The unified cut pipeline: one method combines every active corrector; preview and export consume the same list of ranges.
💡

The preview IS the export: the same AVMutableComposition feeds what you see and what you save. Zero surprises on export.

The app

Architecture & stack

100% native, zero third-party dependencies. SwiftUI for all UI; AVFoundation for PCM reading, composition and export; Speech (iOS 26) with SpeechAnalyzer for on-device transcription with per-word timing; FoundationModels (Apple Intelligence) on-device for optional semantic repetition detection; Core Animation to burn animated subtitles. Lightweight JSON persistence: a project is a reference to the Photos video plus its settings —the video is never copied.

// Nivel de energía de una ventana de muestras PCM (20 ms) en decibelios.
// El mismo cálculo sirve para "pausas largas" cambiando los parámetros.
func rmsDB(_ s: ArraySlice<Int16>) -> Float {
    guard !s.isEmpty else { return -120 }
    var sum = 0.0
    for v in s { let f = Double(v) / 32768.0; sum += f * f }
    let rms = (sum / Double(s.count)).squareRoot()
    return rms > 0 ? Float(20 * log10(rms)) : -120
}
Energy-based silence detection (RMS→dB) reading PCM samples by hand. No libraries, no ML: below the threshold = silence to cut.
ℹ️

Five combinable correctors in a single cut pipeline; adding a new one is just one more branch. The architecture is built to grow.

Apple Intelligence, on-device

Repetitions are detected in two layers. A deterministic layer (n-gram) guarantees a quality floor on every device; on top, an optional, gated Apple Intelligence pass catches semantic redundancies the n-gram misses («I want to go… actually let's go»). The on-device model returns the indices to remove via structured output (guided generation), and never cuts on its own: every suggestion lands in a reviewable list.

import FoundationModels

// Capa de IA OPCIONAL y gated: solo corre si el dispositivo la soporta.
static var isAvailable: Bool {
    if case .available = SystemLanguageModel.default.availability { return true }
    return false
}

// Salida estructurada que el modelo está OBLIGADO a producir:
@Generable
struct RedundantSpanList {
    @Guide(description: "Tramos redundantes a eliminar; vacío si no hay ninguno")
    var spans: [RedundantSpan]
}

@Generable
struct RedundantSpan {
    @Guide(description: "Índice de la primera palabra a eliminar, inclusive")
    var start: Int
    @Guide(description: "Índice de la última palabra a eliminar, inclusive")
    var end: Int
}
Guided generation with @Generable: the on-device model is forced to return typed output with the redundant spans to remove.

Deliverables

  • Silence corrector (configurable RMS→dB)
  • Long-pause corrector (caps to a maximum)
  • Filler corrector (es/en lexicon, reviewable list)
  • Repetition corrector (n-gram + optional Apple Intelligence)
  • On-device automatic subtitles (per-word timing)
  • 6 subtitle animations (karaoke, single word, pop…)
  • WYSIWYG preview (preview = export)
  • Non-destructive editing (Photos reference)

How it grew

  1. Kickoff + engine port

    The editing engine (silences + export) was ported from an earlier project, ideas365.

  2. Unified pipeline + monochrome

    Turning point: unify the cut computation and refactor the brand accent to adaptive monochrome ink.

  3. Four audio correctors

    Silences, pauses, fillers and repetitions, stacked on the unified pipeline.

  4. Repetitions with Apple Intelligence

    Optional, gated AI layer on top of the deterministic n-gram detector.

  5. Free-form subtitles

    Free position, size and animation by percentage; identical in preview and export.

  6. Branding + TestFlight

    Icon Composer app icon and TestFlight upload for testing.

Takeaways

A single source of truth avoids preview/export divergence. A good, well-parameterized primitive yields more than one feature (pauses = silences with different parameters). Two layers (deterministic + AI) beat one: a deterministic floor guarantees universal quality and AI adds the hard cases only where it's available. And in an app whose content IS the video, accent-as-ink —not as a brand color— lets the content breathe and gives maximum-contrast CTAs for free.

Shall we build something together?