Sound Analysis Has No cat_hiss Label
DEV Community

Sound Analysis Has No cat_hiss Label

Apple Sound Analysis can hear a meow. It cannot name a hiss Apple's built-in Sound Analysis model can label cat_meow and cat_purr . It has no cat_hiss class. Point a mic at a real hiss and you often get silence, a generic cat hit, or - worse - snake_hiss . Energy metering only proves something crossed a loudness line. Neither path answers why the cat hissed, and neither path is a finished pet feature. This piece is for the iOS engineer who already knows they will call SNClassifySoundRequest , not for the owner Googling "cat hissing" after a carrier scare. Search intent on that phrase is domain research. Your shipping problem is narrower: the public label list stops at meow and purr. Who hits this wall You are building a pet-audio feature. You need proof, on device, that Apple's free classifier does not cover the sound you care about. A custom Core ML model can invent classes. The stock Sound Analysis path sits one step before that decision - and that is where the gap lives. If your product brief says "detect cat sounds," treat hiss as out of scope for .version1 until you have printed the live class list yourself. Do not ship UI that assumes a missing identifier will appear under a different name. Prove the gap before you build a pipeline You do not need a production recorder to learn the hard limit. You need one finished audio file of a real hiss (or a short take you already recorded) and a read of knownClassifications on the OS you ship. Minimal check - not a day-one product scaffold: import SoundAnalysis func proveCatHissGap(on url: URL) throws { let request = try SNClassifySoundRequest(classifierIdentifier: .version1) // Gap-proof at runtime - do not hardcode a blog dump: print("has cat_hiss?", request.knownClassifications.contains("cat_hiss")) print("has snake_hiss?", request.knownClassifications.contains("snake_hiss")) print("has cat_meow?", request.knownClassifications.contains("cat_meow")) print("has cat_purr?", request.knownClassifications.contains("cat_purr")) let analyzer = try SNAudioFileAnalyzer(url: url) let observer = LabelProbe() try analyzer.add(request, withObserver: observer) analyzer.analyze() observer.top.prefix(8).forEach { print($0.0, String(format: "%.2f", $0.1)) } } final class LabelProbe: NSObject, SNResultsObserving { var top: [(String, Double)] = [] func request(_ request: SNRequest, didProduce result: SNResult) { guard let r = result as? SNClassificationResult else { return } top.append(contentsOf: r.classifications.prefix(5).map { ($0.identifier, $0.confidence) }) } func request(_ request: SNRequest, didFailWithError error: Error) { print("SoundAnalysis error:", error.localizedDescription) } } That is enough to falsify the assumption. You are not copying a production AAC gate, a Documents move race, or a permission dance into a tutorial that pretends to be the feature. Those belong in your app's recorder once you decide classification is still worth calling. What the printout should show on .version1 : cat_hiss is absent; snake_hiss is present; cat_meow / cat_purr are present. The animal block jumps from domestic cat labels into other species. There is no cat_spit and no cat_growl in the public list either. What a real hiss tends to return After a few live takes, patterns repeat even when your recorder code differs from mine: | Clip | Typical top label | |---|---| | Close meow | cat_meow with usable confidence | | Steady purr | cat_purr | | Angry hiss, farther away | silence / weak generic cat | | Angry hiss, close mic | often snake_hiss or junk | | Non-cat broadband noise | trips "something happened," not "cat" | Apple documents that you should read confidence with classification(forIdentifier:) and pick your own threshold (WWDC21 samples use 0.5). Raising the bar to 0.7 cleans false positives. It does not invent a missing class. Why snake_hiss shows up Broadband turbulent airflow looks similar across species to a general audio model. Confidence of 0.3-0.6 on snake_hiss for a cat is a category collision, not a biology claim. Drop any owner-facing string that would surface that identifier. Logging it in debug is fine; shipping it in a toast is not. Loudness is not a species label If you meter while recording, you only learn that energy crossed a tripwire. A common on-device habit is polling averagePower on the order of a few times per second and treating values above roughly −40 dBFS as "had sound." That filter saves empty files and battery. It does not tell you the animal, the affect, or the missing class name. Tune only after you have lived with the room: −35 is stricter and misses soft hisses; −50 grabs fridge hum. Log a kitchen baseline before you treat any threshold as sacred. Permission denied still fails earlier than any of this - Settings → Privacy & Security → Microphone for your target - and NSMicrophoneUsageDescription must exist or the first record call is dead on arrival. Deployment target for the Sound Analysis path you care about here is iOS 16+. None of that metering detail is the product. It is hygiene around a classifier that still cannot say cat_hiss . Honest limit of the stock path When the file path works, you own two things: a clip on disk and a string label (or a ranked list of them). You still do not know whether the hiss meant pain, a new dog in the hallway, or "stop petting." Behaviorists read hissing as a distance-increasing warning - fear or stress more often than pure attack - but that reading needs eyes on ears, tail, and pupils, not a 44.1 kHz buffer. Sound Analysis will not write that sentence. Shipping a custom Core ML sound model is the usual next engineering move if your requirement is a dedicated cat_hiss class under your own control. Budget weeks, not an afternoon: labeled hiss clips, background rejection, on-device size, and App Review scrutiny if copy drifts into animal-health claims. Most teams stop at "we detected a loud event" and leave meaning somewhere else. That "somewhere else" is the real product boundary. Classification ends at a label. Owner-facing sense - a short line that treats the moment as playable, not clinical - is a separate experience layer. It is not a memo app plus a veterinary article tab, and it is not a weekend DIY classifier with a confidence slider. Where the stock path ends - and what sits next to it If your job is to prove Apple's free model cannot name a cat hiss, you are done when knownClassifications.contains("cat_hiss") prints false and a few live takes show silence, weak cat , or snake_hiss . Do not keep pasting recorder + analyzer + UI copy until the tutorial has rebuilt a pet app. If your job is to give a cat owner something after the waveform, you leave the classifier at the edge and hand the moment to a layer that was built for that handoff. On iPhone, Cat Translator is that adjacent edge: record the hiss, get a playful line back, without training your own Core ML sound model and without turning the screen into a clinical aggression guide. The classifier problem stays a classifier problem. The meaning problem stays an experience problem. That split is the honest shipping story. Sound Analysis gives you a label when a class exists. For hiss, the class does not exist. Pretending metering + .version1 closes the owner loop is how products ship snake_hiss into a living room. Checklist before you call the investigation done - [ ] Live knownClassifications printed on the OS you ship - [ ] cat_hiss confirmed absent;snake_hiss /cat_meow /cat_purr noted - [ ] At least a handful of real hiss takes logged with top labels - [ ] No owner-facing UI that displays snake_hiss - [ ] No health claims tied to a Sound Analysis string - [ ] Decision recorded: stay on stock labels, train custom audio ML, or hand meaning to a separate experience layer FAQ Does Sound Analysis support cat hissing in a later classifier version? As of SNClassifierIdentifier.version1 (the built-in identifier Apple documents for SNClassifySoundRequest ), the known label list includes cat_meow and cat_purr but not cat_hiss . Always print knownClassifications on the OS you ship; do not trust a mirrored label dump from 2021 alone. Why does my hiss map to snake_hiss ? Same broadband turbulence family, different animal. Treat mid confidence on snake_hiss as collision evidence for your gap report, not as a fact to show a pet owner. Can a lower meter threshold fix the missing class? No. A looser gate stores more files, including HVAC. You still lack cat_hiss . Thresholds manage silence; they do not extend the ontology. Is averagePower in dBFS? Yes. 0 is full scale. Typical speech sits around −20 to −30. Room tone often sits near −50 to −60. That is why a mid-negative tripwire means "energy moved," not "cat hissed." Should I classify live with SNAudioStreamAnalyzer instead of a file? Use the file probe first so permission, encoding, and labeling failures stay separable. Stream once the gap is proven and you still have a reason to listen continuously - knowing continuous listening will not create the missing class either. Is the next step always a custom Core ML model? Only if you need a first-party cat_hiss label under your model card. If you need an owner-facing line after a hiss, that is outside classification. Build or buy the experience layer; do not force Sound Analysis to narrate intent it cannot see. Top comments (0)

Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.