What a sound is, using the classifier macOS already has, and which song it is, through Shazam's catalogue.
import SoundClassifier
for window in try SoundClassifier.classify(fileAt: url) {
print(window.start, window.top?.name ?? "—", window.top?.confidence ?? 0)
}
try SoundClassifier.knownClasses().count // 303SNClassifySoundRequest(classifierIdentifier: .version1) — Apple's built-in
classifier, already installed. No model to download, no network, no
permission prompt. 303 classes: speech and its varieties (shouting,
whispering, laughter, crying), animals, vehicles, tools, alarms, water, music,
and the noises a room makes.
Deliberately not music analysis.
swift-music-analysis
measures BPM, key and structure; this answers "what is that noise". They
overlap only in that both listen.
The window is fixed at 3 seconds. Audio shorter than one window produces zero results and no error — which reads as "nothing in this audio" rather than "too short to ask". So a short file throws instead, naming both durations.
The confidences are not calibrated. Apple documents no meaning for them.
They order results reliably and mean nothing in absolute terms: a 0.8 is not
"80% likely", it is "more than the 0.6 beside it". minimumConfidence is a
noise gate, not a probability threshold, and this package says so rather than
implying otherwise by naming it one.
Labels stay exactly as the classifier returns them — dog_bark, not "Dog
bark" — because renaming would make the printed name and the filterable label
disagree. name does the prettifying at the point of printing.
if let song = try await SongRecognizer.identify(fileAt: url) {
print(song.title, song.artist ?? "", song.isrc ?? "", song.slicesAgreeing, "of", song.slicesAsked)
}SongRecognizer asks Shazam's catalogue (ShazamKit) about 12-second
slices of a file. Measured on macOS 27.0.1 with a released 6-minute track:
- The catalogue answers only a team-signed binary. The binary must be
signed by a team whose App ID has the ShazamKit App Service
(developer.apple.com › Identifiers), with that bundle id inside the
signature. A command-line tool embeds an
Info.plistas__TEXT,__info_plist. No entitlement, provisioning profile or app bundle is needed.SongRecognizer.isSignedchecks the running process. - An unsigned binary is told nothing useful. It gets the same ShazamCore error 102 as a slice that simply doesn't match. So check the signature first; this package can't tell the two apart.
- Slices, not files. A whole track is refused (ShazamKit 201, duration invalid). Slices go to Shazam spread through the middle, at 40, 65, 20 and 85 %.
- One slice is not believed. A slice of the bare DJ drum intro matched a
different trance track. Slices are asked until two name the same
recording (by ISRC), and the answer carries
slicesAgreeingofslicesAsked. - What comes back: title, artist, genres, ISRC, Apple Music and web links, artwork, and where in the song the slice was (±2 s of the truth). A match took 1.8–2.6 s.
Only a fingerprint of each slice leaves the machine, not the audio.
7 tests on synthetic audio: the classifier is present without a download, the
window really is 3 seconds, short audio is refused rather than silently empty,
results come back strongest-first, and the confidence gate actually drops
things. 7 more for songs: the slicing rule, signatures from stereo 48 kHz
audio, the too-short and unreadable cases, the agreement vote (a lone or
outvoted slice loses), and that a test build is not team-signed. The
catalogue itself is checked on the signed hear release.
MIT.