KeyDetectionKit is a Swift package for detecting the musical key of a local audio file and returning both standard key names and Camelot notation.
It follows the same segment-based HPCP matching approach used in Mocawave Player, packaged as a small standalone library for Apple platforms.
- Detects major and minor keys from local audio files
- Returns both traditional key names like
C Majorand Camelot values like8B - Produces structured confidence and uncertainty metadata
- Includes a standalone
CamelotConverterfor key/Camelot lookups - Supports
macOS 12+andiOS 15+
- Swift 6
- macOS 12 or later
- iOS 15 or later
Add the package with Swift Package Manager:
dependencies: [
.package(url: "https://github.com/hPerezz/key-detection-kit.git", from: "1.0.0")
]Then add the product to your target:
.target(
name: "YourApp",
dependencies: [
.product(name: "KeyDetectionKit", package: "KeyDetectionKit")
]
)Pass a local file URL that AVFoundation can open:
import Foundation
import KeyDetectionKit
let url = URL(fileURLWithPath: "/path/to/track.wav")
let result = try KeyDetector.analyze(url: url)
if result.isResolved {
print(result.key ?? "")
print(result.camelot ?? "")
print(result.confidence)
} else {
print(result.status)
print(result.uncertaintyReason ?? .insufficientTonalFrames)
print(result.runnerUpKey ?? "No runner-up")
}If you want progress logs during analysis:
let result = try KeyDetector.analyze(url: url) { message in
print(message)
}Example log output:
[Key] Loading audio...
[Key] Segments: 1 x 12.0s target windows
[Key] Segment 1/1: 0.0s -> 12.0s
[Key] Result: C Major confidence: 0.84
KeyDetector.analyze(url:) returns KeyDetectionResult:
status:.resolvedor.uncertainkey: detected key name such asA Minorcamelot: Camelot value such as8Aconfidence: normalized confidence score from0...1runnerUpKey: second-best candidate when availableuncertaintyReason: why the result was left unresolved
When the result is uncertain, key and camelot are nil.
You can also use the converter without running audio analysis:
import KeyDetectionKit
let camelot = CamelotConverter.camelot(forKeyName: "C Major")
let keyName = CamelotConverter.keyName(forCamelot: "8A")KeyDetector.analyze(url:) can throw:
KeyDetectionError.invalidAudioKeyDetectionError.analysisUnavailableKeyDetectionError.silentAudio
- The detector analyzes tonal content, not metadata tags.
- Ambiguous or low-information material may return
.uncertain. - Short, silent, or noise-heavy files are less likely to produce a resolved key.