Skip to main content
Code samples

Performance Troubleshooting

File Processing Is Slowโ€‹

Expected performance: ~20ร— faster than realtime on iPhone 14+. A 10-minute file should complete in ~28 seconds.

If significantly slower:

  1. Processor reuse โ€” are you creating a new NCKitProcessor per file? This adds 50โ€“200ms per file:

    // SLOW
    for url in files {
    let proc = try NCKitProcessor(modelURL: modelURL) // โŒ 100ms per file
    try NCKitFileProcessor.processFile(..., processor: proc)
    }

    // FAST
    let proc = try NCKitProcessor(modelURL: modelURL) // โœ… once
    for url in files {
    try NCKitFileProcessor.processFile(..., processor: proc)
    }
  2. Unnecessary resampling โ€” if your recordings are already 48 kHz mono, ensure they're saved in that format to skip the AVAudioConverter step.

  3. Task priority โ€” use .userInitiated for processing tasks:

    Task.detached(priority: .userInitiated) { ... }

High CPU During Real-Time Processingโ€‹

Symptom: Device heats up, CPU usage >25% while NC is active.

Solutions:

  1. Reduce attenuation โ€” lower attenLimDb slightly reduces post-processing work:

    processor.setAttenLim(60)  // was 100
  2. Increase buffer size โ€” larger IO buffer means fewer interrupts per second:

    try AVAudioSession.sharedInstance().setPreferredIOBufferDuration(0.02) // 20ms instead of 10ms

    Note: This increases latency from 10ms to 20ms.

  3. Monitor thermal state and reduce processing when throttled:

    NotificationCenter.default.addObserver(
    forName: ProcessInfo.thermalStateDidChangeNotification,
    object: nil, queue: .main
    ) { _ in
    let state = ProcessInfo.processInfo.thermalState
    if state >= .serious {
    processor.setAttenLim(40) // reduce aggressiveness
    } else {
    processor.setAttenLim(100) // restore
    }
    }

Audio Glitches / Dropoutsโ€‹

Symptom: Clicks, pops, or dropouts in real-time processing.

Root cause: Almost always memory allocation in the audio render callback.

Checklist:

  • outputBuffer pre-allocated before installTap
  • No [Float](repeating:count:) inside the tap closure
  • No print() statements inside the tap closure
  • No DispatchQueue.main.async inside the tap closure
  • No Swift actor access inside the tap closure

Profile with Instruments:

  • Time Profiler โ†’ look for allocation activity on the audio thread
  • Allocations โ†’ filter by "Audio I/O Thread" โ€” should show zero allocations per frame

High Memory During File Processingโ€‹

Symptom: Memory grows steadily during long file processing.

Cause: You may be accumulating processed samples in a [Float] array in memory.

NCKit's NCKitFileProcessor itself uses constant memory โ€” but if you load the output WAV back into memory with Data(contentsOf: url) or a custom WAV loader on a large file, that loads the entire file at once.

Solution: Process in chunks or stream the output directly to its destination (Files.app, network, etc.) without loading it into memory.