Skip to content

Support incremental file loading#507

Open
a2they wants to merge 1 commit into
mainfrom
oss/streamFile
Open

Support incremental file loading#507
a2they wants to merge 1 commit into
mainfrom
oss/streamFile

Conversation

@a2they

@a2they a2they commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Add incremental audio file loading so long-form transcription reads files in bounded-memory chunks rather than loading the entire file into memory. Full-file loading stays the default, so existing behavior is unchanged.

Incremental file loading

  • AudioProcessor.loadFileIncrementally streams a file as an AsyncThrowingStream with backpressure — at most chunkBufferSize chunks are queued before the producer suspends (IncrementalLoadController).
  • Chunk boundaries reuse the full-file VADAudioChunker + internal EnergyVAD, carrying partially-decided chunks across staging buffers, so incremental output matches a single full-file load exactly; time-based cutting is the fallback.
  • The 16 kHz mono read path tops up short reads (seen with 32-bit float PCM near EOF) so segmented reads are byte-identical to a full-file read.
  • Multi-file incremental transcription honors concurrentWorkerCount.

AudioInputOptions

  • Renamed AudioInputConfigAudioInputOptions (old name kept as a deprecated typealias); it bundles channelMode and audioLoadingMode.
  • AudioInputOptions.AudioLoadingMode: .fullFile (default) and .incremental(chunkDuration:chunkBufferSize:), plus an .incremental shorthand using the default duration/buffer size.
  • File-path transcribe / transcribeWithResults take audioInputOptions: AudioInputOptions? = nil, right after the audio path and above decodeOptions.
  • WhisperKitConfig.audioInputConfig is deprecated — pass audioInputOptions per call instead.

---------

Co-authored-by: Andrey Leonov <aleonov@gmail.com>
Co-authored-by: ZachNagengast <znagengast@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an incremental (bounded-memory) audio file loading mode to WhisperKit so long-form transcription can stream audio from disk in chunks, while keeping full-file loading as the default. It also renames/configures audio input settings via a new AudioInputOptions type and wires the new loading mode through the library API, CLI, and documentation.

Changes:

  • Add incremental file streaming in AudioProcessor.loadFileIncrementally with explicit backpressure (IncrementalLoadController) and VAD-consistent chunk boundaries.
  • Introduce AudioInputOptions (renaming AudioInputConfig via deprecated typealias) with AudioLoadingMode to choose .fullFile vs .incremental(...), and thread this through WhisperKit.transcribe* APIs.
  • Add new unit tests for incremental loading behavior + update CLI flags and README documentation.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Tests/WhisperKitTests/UnitTests.swift Updates tests to use per-call AudioInputOptions instead of config-level AudioInputConfig.
Tests/WhisperKitTests/TestUtils.swift Updates channel-mode helper type and adds an async timeout helper used by new tests.
Tests/WhisperKitTests/AudioProcessorTests.swift Adds coverage for incremental chunking invariants, parity with full-file chunking, backpressure, termination behavior, and multi-file concurrency/order.
Sources/WhisperKit/Core/WhisperKit.swift Adds per-call audioInputOptions, incremental transcription paths, and stream-based transcription helper; updates segment offset handling.
Sources/WhisperKit/Core/Configurations.swift Deprecates config-level audio input config and stores AudioInputOptions in a backing property.
Sources/WhisperKit/Core/Audio/VoiceActivityDetector.swift Marks base VAD type as @unchecked Sendable with documentation about subclass requirements.
Sources/WhisperKit/Core/Audio/AudioProcessor+IncrementalLoading.swift Implements incremental audio streaming with VAD-based boundaries and bounded buffering/backpressure.
Sources/WhisperKit/Core/Audio/AudioProcessor.swift Renames input config type, adds AudioLoadingMode, and fixes short-read behavior in the 16kHz mono fast path via readFully.
Sources/ArgmaxCLI/TranscribeCLIUtils.swift Adds helper to derive AudioInputOptions from CLI args, defaulting to full-file loading.
Sources/ArgmaxCLI/TranscribeCLIArguments.swift Adds CLI flags/options for incremental loading and tuning chunk duration/buffer size.
Sources/ArgmaxCLI/TranscribeCLI.swift Validates incremental-loading args and passes audioInputOptions into transcription.
README.md Documents the new incremental loading option and updates the quick example.
Examples/WhisperAX/.../Package.resolved Updates Swift Argument Parser pin used by the example workspace.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 988 to 992
open func transcribe(
audioArray: [Float],
audioArrayOffset: Int = 0,
decodeOptions: DecodingOptions? = nil,
callback: TranscriptionCallback? = nil,
Comment on lines +845 to 849
let seekTimeOffset = Float(seekOffsets[windowId]) / Float(WhisperKit.sampleRate)
let adjustedSegments = segments.map {
TranscriptionUtilities.updateSegmentTimings(segment: $0, seekTime: seekTimeOffset)
}
segmentDiscoveryCallback?(adjustedSegments)
Comment on lines +1209 to +1222
let seekTimeOffset = Float(chunk.audioChunk.seekOffsetIndex) / Float(WhisperKit.sampleRate)
let adjustedResults = chunkResults.map { result in
let adjustedSegments = result.segments.map { segment in
TranscriptionUtilities.updateSegmentTimings(segment: segment, seekTime: seekTimeOffset)
}

return TranscriptionResult(
text: result.text,
segments: adjustedSegments,
language: result.language,
timings: result.timings,
seekTime: seekTimeOffset + (result.seekTime ?? 0)
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants