SmartSpeedKit is a Swift package for seekable, offline smart-speed playback of spoken-word audio.
It provides:
- A timeline model (
SmartSpeedAnalysis) that marks compressible gaps. - Segment generation (
SegmentBuilder) that assigns different playback rates to speech vs gaps. - A seekable AVAudioEngine-based player (
SeekableSmartSpeedPlayer). - Optional voice enhancement (EQ + dynamics processor).
- Bidirectional timeline mapping (
SmartSpeedTimeMapper) for progress UI and scrubbing.
- iOS 15+
- macOS 12+
- Swift Package Manager
Add this package to your Package.swift dependencies and target dependencies.
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "YourApp",
platforms: [
.iOS(.v15),
.macOS(.v12)
],
dependencies: [
.package(url: "https://github.com/<your-org>/SmartSpeedKit.git", branch: "main")
],
targets: [
.target(
name: "YourApp",
dependencies: ["SmartSpeedKit"]
)
]
)CompressibleGap: start/end interval in original timeline seconds.SmartSpeedAnalysis: total duration + ordered list ofCompressibleGapvalues.PlaybackSegment: frame-range + playback rate for one scheduled segment.SegmentBuilder: createsPlaybackSegmentvalues from an audio file + analysis.SeekableSmartSpeedPlayer: engine-backed player with play/pause/stop/seek.VoiceEnhancementChain: optional spoken-word EQ + dynamics processing.SmartSpeedTimeMapper: convert between original time and elapsed smart-speed time.
import AVFoundation
import SmartSpeedKit
let url = URL(fileURLWithPath: "/path/to/audio.m4a")
let file = try AVAudioFile(forReading: url)
// Build or load your analysis from a detector in your app.
let analysis = SmartSpeedAnalysis(
duration: 1800,
gaps: [
.init(start: 12.4, end: 12.9),
.init(start: 47.2, end: 48.0)
]
)
let player = SeekableSmartSpeedPlayer()
player.speechRate = 1.1
player.gapRate = 2.4
try player.prepare()
player.load(file: file, analysis: analysis)
player.play()
// Later...
player.seek(to: 300) // original timeline secondstry await player.enableVoiceEnhancement()This inserts:
AVAudioUnitEQ(spoken-word preset)kAudioUnitSubType_DynamicsProcessor(spoken-word dynamics preset)
Use this after prepare() and before playback (or while stopped).
When smart-speed is active, elapsed playback time diverges from original timeline time. Use the mapper for UI progress and scrubbing:
if let mapper = player.makeTimeMapper() {
let elapsed = mapper.elapsedTime(forOriginalTime: 600)
let original = mapper.originalTime(forElapsedTime: elapsed)
print(elapsed, original)
}SmartSpeedKitexpects you to provideSmartSpeedAnalysis(gap detection is app-specific).- Gap intervals should be sorted and non-overlapping for best results.
- All times are in seconds; playback scheduling is frame-based.
Run package tests:
swift test