Vigilant Ear

Custom Sound Packs — How to Build and Import Your Own

Vigilant Ear can learn new sounds. A custom sound pack teaches the app to recognize sounds Apple's built-in detector doesn't know — your local birds, a specific machine at work, your building's odd hallway buzzer. You train a small model on a Mac (no coding required), zip it up with two small text files, and import it on your iPhone.

Custom packs stack on top of the built-in detector. Turning a pack on never turns anything else off — sirens, alarms, and every other safety sound keep working exactly as before.

You'll need: a Mac with Xcode's Create ML app (free), audio recordings of your sounds, and Power Pack+ on your iPhone (the free trial counts).


Hard requirements — get these exactly right

A pack that ignores any of these will import but behave badly (constant false alerts, or nothing detected). These are not suggestions:

  1. Include a Background class — mandatory, not optional. Your model must have a class trained on your real ambient environments (quiet room, street, the fan running). Fill it with 15+ real recordings and mark it with "category": "ignored" and "threshold": 1.1 in profiles.json. Without a Background class your pack will fire constantly on silence — a sound classifier is forced to pick one of its classes for every moment of audio, so with no "none of these" bucket it labels your quiet room as whatever it most resembles.
  2. Trim silence out of your training clips. A clip labeled "Owl" that is 20 seconds of silence with one hoot teaches the model that silence is an owl. Crop clips tight to the target sound, or the model learns the gaps.
  3. Name the model file exactly model.mlmodel or model.mlpackage. Any other name → import fails.
  4. Use a Create ML Sound Classification model. Image/text/tabular models are rejected.
  5. profiles.json keys must exactly match the model's class labels — i.e. your training folder names, case and underscores included.
  6. Add gateClasses (see below). Without it, music and TV will trigger the pack. This is the single biggest false-alarm control.
  7. Zip the files at the top level (or inside one folder — no deeper). pack.json must be findable.
  8. Balance your classes. Don't give one class 100 clips and another 10 — the model will lean toward the big one. Cap generously-sampled classes so counts are within ~3× of each other.

The rest of this guide walks through each of these in order.


Step 1 — Gather training audio

Make a folder for each sound you want recognized, named for that sound, and fill it with example recordings:

TrainingData/
  Mourning_Dove/        ← 20+ clips of mourning doves
  House_Finch/          ← 20+ clips of house finches
  Background/           ← 20+ clips of your ambient environment WITHOUT the sounds

Tips that make a real difference:

Step 2 — Train the model in Create ML

  1. Open Create ML (on a Mac with Xcode: Xcode menu → Open Developer Tool → Create ML), and create a new Sound Classification project.
  2. Drag your TrainingData folder into Training Data.
  3. Click Train. A few hundred clips train in minutes.
  4. Check the accuracy tab — if one class scores poorly, it needs more or more-varied clips.
  5. On the Output tab, click Get and save the model as model.mlmodel (or model.mlpackage — both work). The filename must be exactly model.mlmodel or model.mlpackage.

Step 3 — Write pack.json

A tiny manifest describing the pack:

{
  "id": "com.example.pack.socalbirds",
  "name": "SoCal Birder's Companion",
  "version": "1.0",
  "author": "Your Name",
  "classes": ["Mourning_Dove", "House_Finch", "Background"],
  "gateClasses": ["bird", "bird_vocalization", "bird_chirp_tweet", "pigeon_dove_coo", "crow_caw"]
}

gateClasses — let Apple's model be your bouncer

Your model is a specialist: it's good at telling which of your sounds it's hearing, but it has no idea what "not one of my sounds" is (that's what the Background class helps with). Apple's built-in classifier is a generalist trained on ~300 everyday sounds — it's very good at the coarse question "is there a bird at all?"

gateClasses chains them: your pack's detections are only reported when Apple's model is concurrently hearing one of the listed built-in categories. A bird pack gates on Apple's bird labels, so if Apple doesn't think there's a bird, your pack stays silent — no matter how confident it is. This single line eliminates the vast majority of music, TV, and quiet-room false alarms, because Apple's model scores those far below the gate. Leave it out and the pack runs ungated (fine for testing, chatty in the real world).

Gating is only available when Apple already has a category near your sound. If your pack is for something Apple's ~300-class model doesn't know — a specific factory machine, a medical-device beep, a custom doorbell — there is no built-in label to gate on, so you leave gateClasses out and the pack runs ungated. That's expected, not a mistake. For those packs your Background class stops being one defense among several and becomes the only thing standing between you and constant false alerts — so invest heavily in it (lots of real ambient recordings) and raise your per-class thresholds.

Gate a bird pack on the generic Apple bird labels plus any specific ones your model can actually name: bird, fowl, bird_vocalization, bird_chirp_tweet, bird_squawk, bird_flapping — and, if your pack has the matching species, crow_caw and pigeon_dove_coo. Other pack types pick their own gates from the full list of built-in sound identifiers in the appendix below — e.g. a dog-breed pack gates on dog_bark/dog_howl, a vehicle pack on engine/truck.

muteClasses — defer to Apple on sounds your model can't name

gateClasses opens your pack when Apple thinks there's a bird. But Apple can specifically name some birds your model may not cover — a duck, goose, owl, turkey, chicken, or rooster. If Apple hears a duck and your pack has no duck class, your model will force-sort that quack into its nearest species and confidently call it the wrong bird. That's a misidentification, not a false alarm from silence — and gateClasses alone won't stop it, because a duck also trips the generic bird gate.

muteClasses fixes it: when Apple is confident about one of these labels, your pack stays silent for that moment and defers to Apple's specific call. List the built-in labels for sounds you don't cover:

"muteClasses": ["owl_hoot", "duck_quack", "goose_honk", "turkey_gobble", "chicken", "chicken_cluck", "rooster_crow"]

Rule of thumb: a specific Apple bird label goes in gateClasses if your model has a matching (or better) class for it, and in muteClasses if it doesn't. Everything Apple can name that you can't → mute it, and let Apple be right.

Step 4 — Write profiles.json (optional, recommended)

This controls how each sound looks and feels in the app — one entry per class, keyed by the exact folder/label name:

{
  "Mourning_Dove": {
    "displayName": "Mourning Dove",
    "hapticCount": 1,
    "emergencyTier": "none",
    "category": "animal",
    "icon": "bird",
    "color": "teal",
    "threshold": 0.5,
    "maxRange": 150
  },
  "House_Finch": {
    "displayName": "House Finch",
    "hapticCount": 1,
    "category": "animal",
    "icon": "bird"
  },
  "Background": {
    "category": "ignored",
    "threshold": 1.1
  }
}

Every key is optional — omit anything and a sensible default applies:

Key What it does Default
displayName Name shown on the map and in alerts Label with underscores → spaces, capitalized
hapticCount Vibration pulses when the sound is first revealed (0 = none) 0
emergencyTier "none" for typical sounds. Leave it "none" unless the sound genuinely warrants an urgent alert "none"
category Grouping: animal, vehicle, medium, quiet, or misc misc
icon An SF Symbols name, e.g. bird, pawprint, fan, bell waveform
color Dot/icon tint: red, blue, cyan, pink, brown, mint, orange, gray, teal, purple, or "r,g,b" with values 0–1 teal
threshold Confidence (0–1) required before the sound registers. Raise it if a class false-alarms; lower it if it's missed 0.5
maxRange Rough maximum detection range shown on the map, in feet 150

Your Background class needs the special entry shown above: "threshold": 1.1 makes it impossible to report (confidence never exceeds 1.0), so it silently absorbs ambient audio instead of ever showing up as a detection. Don't just omit it — an unlisted class still gets the default 0.5 threshold and would appear in the app as a generic sound.

Step 5 — Zip it

Select the three files — pack.json, profiles.json, model.mlmodel — right-click, and Compress. Zipping the enclosing folder instead also works; the app looks one folder deep.

MyPack.zip
├── pack.json
├── profiles.json
└── model.mlmodel

Get the zip to your iPhone however you like: AirDrop, iCloud Drive, Mail, Messages.

Step 6 — Import on your iPhone

  1. Open Vigilant Ear → gear menu → Power Pack+.
  2. Scroll to Custom Sound Packs (BYOM) and tap Import Custom Pack (.zip).
  3. Pick your zip in the Files browser.

The pack appears in the list with its sound count, already LIVE. From here you can:

Detected sounds show up like any other: a dot on the map with your icon and color, the display name in alerts, and your configured haptics.

A couple of built-in behaviors to know about: custom pack detections are not relayed to Constellation mesh peers (other phones won't have your pack installed), and pack sounds require two consecutive detections before alerting, which filters one-frame false positives.

Troubleshooting

Message / symptom Cause and fix
"No pack.json found in the zip" The zip's files are nested more than one folder deep, or pack.json is misnamed. Re-zip with the three files at the top level.
"pack.json could not be read" JSON syntax error — a missing comma or quote. Validate it (e.g. paste into a JSON checker) and re-zip.
"No model.mlpackage or model.mlmodel found" The model file has a different name. Rename it to exactly model.mlmodel (or model.mlpackage).
"The model is not a sound classifier…" The model isn't a Create ML Sound Classification model — image/text/tabular models can't be used. Retrain with the Sound Classification template.
Pack imports but a sound never triggers Its confidence isn't reaching the threshold. Lower that class's threshold (try 0.35), and add more varied training clips.
A sound triggers constantly on ambient noise, music, or TV Add gateClasses to pack.json (see above) — this is the biggest lever by far. Also add/expand the Background class with recordings of the offending environment, then retrain and re-import. Raising the class threshold (e.g. 0.8) helps too.
Real sounds are detected, but so are a few wrong ones Two consecutive detections are already required, and gateClasses filters most noise. For the stragglers, nudge that specific class's threshold up toward 0.85–0.9.
Names/haptics from profiles.json don't apply The keys in profiles.json must match the model's class labels (your training folder names) exactly, including case and underscores.

Updating a pack

Retrain or edit, re-zip, and import again with the same id in pack.json — the old version is replaced in place.


Appendix: Built-in Sound Identifiers (iOS 26.5)

These are the built-in sound categories Apple's on-device Sound Analysis classifier can recognize — the labels available for gateClasses and muteClasses above. Apple no longer publishes this list on their developer site, so the table below was read directly from the classifier on-device (SNClassifierIdentifier.version1).

Known classifications as of July 2026 (iOS 26.5) — 303 labels. Apple can add, remove, or rename these in any OS update, so treat this as a point-in-time snapshot: gating on a label that a future OS drops simply means that gate never fires (your pack stays silent), and a newly added label won't exist until you gate on it. Use the exact spelling shown (lowercase, underscores).

# Identifier Identifier Identifier Identifier
1 accordion crowd humming singing_bowl
2 acoustic_guitar crumpling_crinkling insect sink_filling_washing
3 air_conditioner crushing keyboard_musical siren
4 air_horn crying_sobbing keys_jangling sitar
5 aircraft cutlery_silverware knock skateboard
6 airplane cymbal laughter skiing
7 alarm_clock didgeridoo lawn_mower slap_smack
8 ambulance_siren disc_scratching lion_roar slurp
9 applause dishes_pots_pans liquid_dripping smoke_detector
10 artillery_fire dog liquid_filling_container snake_hiss
11 babble dog_bark liquid_pouring snake_rattle
12 baby_crying dog_bow_wow liquid_sloshing snare_drum
13 baby_laughter dog_growl liquid_splashing sneeze
14 bagpipes dog_howl liquid_spraying snicker
15 banjo dog_whimper liquid_squishing snoring
16 basketball_bounce door liquid_trickle_dribble speech
17 bass_drum door_bell mallet_percussion squeak
18 bass_guitar door_slam mandolin steel_guitar_slide_guitar
19 bassoon door_sliding marimba_xylophone steelpan
20 bathtub_filling_washing double_bass mechanical_fan stream_burbling
21 battle_cry drawer_open_close microwave_oven subway_metro
22 bee_buzz drill mosquito_buzz synthesizer
23 beep drum motorboat_speedboat tabla
24 bell drum_kit motorcycle tambourine
25 belly_laugh duck_quack music tap
26 bicycle electric_guitar nose_blowing tearing
27 bicycle_bell electric_piano oboe telephone
28 bird electric_shaver ocean telephone_bell_ringing
29 bird_chirp_tweet electronic_organ orchestra theremin
30 bird_flapping elk_bugle organ thump_thud
31 bird_squawk emergency_vehicle owl_hoot thunder
32 bird_vocalization engine percussion thunderstorm
33 biting engine_accelerating_revving person_running tick
34 blender engine_idling person_shuffling tick_tock
35 boat_water_vehicle engine_knocking person_walking timpani
36 boiling engine_starting piano toilet_flush
37 booing eruption pig_oink toothbrush
38 boom finger_snapping pigeon_dove_coo traffic_noise
39 bowed_string_instrument fire playing_badminton train
40 bowling_impact fire_crackle playing_hockey train_horn
41 brass_instrument fire_engine_siren playing_squash train_wheels_squealing
42 breathing firecracker playing_table_tennis train_whistle
43 burp fireworks playing_tennis trombone
44 bus flute playing_volleyball truck
45 camera fly_buzz plucked_string_instrument trumpet
46 car_horn foghorn police_siren tuning_fork
47 car_passing_by fowl power_tool turkey_gobble
48 cat french_horn power_windows typewriter
49 cat_meow frog printer typing
50 cat_purr frog_croak race_car typing_computer_keyboard
51 cello frying_food rail_transport ukulele
52 chainsaw gargling railroad_car underwater_bubbling
53 chatter gasp rain vacuum_cleaner
54 cheering giggling raindrop vehicle_skidding
55 chewing glass_breaking rapping vibraphone
56 chicken glass_clink ratchet_and_pawl violin_fiddle
57 chicken_cluck glockenspiel rattle_instrument water
58 children_shouting gong reverse_beeps water_pump
59 chime goose_honk ringtone water_tap_faucet
60 choir_singing guitar rooster_crow waterfall
61 chopping_food guitar_strum rope_skipping whale_vocalization
62 chopping_wood guitar_tapping rowboat_canoe_kayak whispering
63 chuckle_chortle gunshot_gunfire sailing whistling
64 church_bell gurgling saw whoosh_swoosh_swish
65 civil_defense_siren hair_dryer saxophone wind
66 clapping hammer scissors wind_chime
67 clarinet hammond_organ screaming wind_instrument
68 click harmonica scuba_diving wind_noise_microphone
69 clock harp sea_waves wind_rustling_leaves
70 coin_dropping harpsichord sewing_machine wood_cracking
71 cough hedge_trimmer sheep_bleat writing
72 cow_moo helicopter shofar yell
73 cowbell hi_hat shout yodeling
74 coyote_howl hiccup sigh zipper
75 cricket_chirp horse_clip_clop silence zither
76 crow_caw horse_neigh singing

Wingdings, Inc.

© 2026 Wingdings, Inc.
All rights reserved.
Patent Pending