Skip to content

Fix silence detection for multi-channel microphones - #245

Merged
jatinkrmalik merged 3 commits into
mainfrom
fix/silence-detection
Sep 3, 2026
Merged

Fix silence detection for multi-channel microphones#245
jatinkrmalik merged 3 commits into
mainfrom
fix/silence-detection

Conversation

@jatinkrmalik

@jatinkrmalik jatinkrmalik commented Aug 31, 2026

Copy link
Copy Markdown
Member

Summary

  • preserve speech from multi-channel microphones and audio interfaces instead of relying on Core Audio's broken implicit downmix
  • let users select and persist the physical input channel for multi-channel interfaces, keeping capture stable if loopback or another input is louder
  • invalidate that channel mapping when the active device UID or channel topology changes, falling back safely to channel 1
  • bind the input tap to the hardware format that is live after USB or Bluetooth route setup
  • make the silence timer explicitly track continuous silence and restart its full countdown whenever speech resumes
  • replace the 0.5 to 5 second slider with a custom field that accepts 0.5 to 300 seconds

Root cause

VocaMac converted the microphone buffer directly from the device format to mono. On macOS, that conversion reads only channel 0 for stereo input and can return an all-zero buffer for devices with more than two channels. The reported EVO4 route opened as 44.1 kHz with four channels, so its input was converted to silence.

Because no buffer crossed the speech threshold, the silence timestamp never moved. The configured silence duration then behaved like a maximum recording duration, and the final zero-sample check reported that the microphone was unavailable even though Core Audio was delivering buffers.

Multi-channel buffers are now reduced to the user-selected physical channel before sample-rate conversion. The selection remains fixed for the entire recording so a louder loopback or secondary input cannot replace the microphone.

The saved index is tied to the interface UID and channel count. Both settings and the audio engine revalidate that mapping, including after an in-progress route restart, so a system-default device change or interface mode change cannot reuse a stale channel.

The permissions reset in the supplied log separately explains the temporary Accessibility and Input Monitoring failure. Those permissions recovered before the repeated zero-audio captures.

Testing

  • swift test --filter AudioEngineTests (14 tests, 0 failures)
  • swift test --filter AppStateRecordingTests (37 tests, 0 failures)
  • swift test (442 tests, 1 expected hardware-dependent skip, 0 failures)
  • swift build
  • added deterministic coverage for selected-channel conversion on four-channel input, competing loopback input, stale device/layout mappings, invalid-index fallback, selection forwarding, silence countdown reset after speech, live tap format selection, and custom duration bounds

@netlify

netlify Bot commented Aug 31, 2026

Copy link
Copy Markdown

Deploy Preview for voca-mac canceled.

Name Link
🔨 Latest commit ac4ae8c
🔍 Latest deploy log https://app.netlify.com/projects/voca-mac/deploys/6a97e4a26252480008b7a75e

@github-actions github-actions Bot added app bug Something isn't working ci and removed bug Something isn't working ci labels Aug 31, 2026
@jatinkrmalik
jatinkrmalik marked this pull request as ready for review August 31, 2026 19:58
@jatinkrmalik

Copy link
Copy Markdown
Member Author

/build

@github-actions

Copy link
Copy Markdown

PR Build started for 190e488

Build signed & notarized DMG... this usually takes 10–20 minutes.

Watch the build →

@greptile-apps

greptile-apps Bot commented Aug 31, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes multi-channel microphone capture by persisting a physical input-channel selection, validating it against the live device identity and topology, and extracting that channel before sample-rate conversion. It also resets silence timing after speech and expands the configurable silence duration.

  • Adds persisted, device-bound input-channel selection.
  • Revalidates channel mappings during cold starts and route restarts.
  • Uses the live input-tap format and explicitly extracts multi-channel audio.
  • Tracks continuous silence independently of total recording time.
  • Expands silence duration input to 0.5–300 seconds.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
Sources/VocaMac/Services/AudioEngine.swift Adds live-format input taps, device-bound channel validation, selected-channel extraction, and continuous-silence tracking; the previously reported channel-selection issues are addressed.
Sources/VocaMac/Models/AppState.swift Persists channel mapping metadata and forwards the selected device/channel layout into recording startup.
Sources/VocaMac/Views/SettingsView.swift Adds physical input-channel selection and bounded custom silence-duration entry.
Sources/VocaMac/Models/SilenceDetectionSettings.swift Centralizes silence-duration defaults and validation bounds.
Tests/VocaMacTests/ServiceTests.swift Adds regression coverage for fixed-channel capture, stale mappings, live tap format, conversion, and silence countdown reset.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[Saved device UID, channel count, and channel] --> B[Recording startup or route restart]
    B --> C{Mapping matches live UID and topology?}
    C -- Yes --> D[Use selected physical channel]
    C -- No --> E[Fall back to channel 1]
    D --> F[Extract mono buffer]
    E --> F
    F --> G[Convert to 16 kHz Float32]
    G --> H[Speech and silence detection]
Loading

Reviews (4): Last reviewed commit: "fix: invalidate stale audio channel mapp..." | Re-trigger Greptile

Comment thread Sources/VocaMac/Services/AudioEngine.swift Outdated
@jatinkrmalik
jatinkrmalik marked this pull request as draft August 31, 2026 20:03
@jatinkrmalik
jatinkrmalik marked this pull request as ready for review August 31, 2026 20:22
Comment thread Sources/VocaMac/Services/AudioEngine.swift Outdated
@jatinkrmalik
jatinkrmalik marked this pull request as draft August 31, 2026 20:28
@jatinkrmalik
jatinkrmalik marked this pull request as ready for review August 31, 2026 20:47
@jatinkrmalik

Copy link
Copy Markdown
Member Author

/build

@github-actions

Copy link
Copy Markdown

PR Build started for dae1c8e

Build signed & notarized DMG... this usually takes 10–20 minutes.

Watch the build →

@github-actions

Copy link
Copy Markdown

PR Build ready!

DMG VocaMac-0.9.0-pr.245+dae1c8e-arm64.dmg
Size 29M
Branch fix/silence-detection
Commit dae1c8e
Signed ✅ Developer ID
Notarized ✅ Apple

📥 Install

  1. Click the DMG link above to download
  2. Open the DMG and drag VocaMac to Applications (replace existing)
  3. Open VocaMac — No Gatekeeper warnings, no permission resets
SHA-256 checksum
3b1597b81012f3cfde6d2e4288e711920300c7f06a6b80bd2e47ca685ba92cee  VocaMac-0.9.0-pr.245+dae1c8e-arm64.dmg

💡 Comment /build or /build-quick to rebuild.

@fraser-atlassian

Copy link
Copy Markdown

/build

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

PR Build started for ac4ae8c

Build signed & notarized DMG... this usually takes 10–20 minutes.

Watch the build →

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

PR Build ready!

DMG VocaMac-0.9.0-pr.245+ac4ae8c-arm64.dmg
Size 29M
Branch fix/silence-detection
Commit ac4ae8c
Signed ✅ Developer ID
Notarized ✅ Apple

📥 Install

  1. Click the DMG link above to download
  2. Open the DMG and drag VocaMac to Applications (replace existing)
  3. Open VocaMac — No Gatekeeper warnings, no permission resets
SHA-256 checksum
63d8ce89da9be01807ed9d6aa3ab388256aadf2ee13c6b53a7f31779b5071d52  VocaMac-0.9.0-pr.245+ac4ae8c-arm64.dmg

💡 Comment /build or /build-quick to rebuild.

@jatinkrmalik
jatinkrmalik merged commit 0629ef1 into main Sep 3, 2026
10 checks passed
@jatinkrmalik
jatinkrmalik deleted the fix/silence-detection branch September 3, 2026 03:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants