💤

VRChいびきを検知して自動でマイクをミュートするツールを作った話

に公開

はじめに

自己満個人ツールを片隅で作っていたのですが、
たまにはアウトプットしてみようかなと思って始めて記事書いてます。

なにつくったの?

最近、VRChatやらにはまり夜な夜なVRでインしていた時に
ふと、寝落ちしていました💤

起きてから気が付いたのですかミュートが外れており...
やらかしたかなと思ったことがきっかけで、本アプリを作ってみました

何ができるの?

Windowsで動くシンプルなアプリです。
主な機能はこんな感じです。

  • いびき検出:
    • マイクの音をリアルタイムで分析して、いびきを検知します。
  • VRChat自動ミュート連携:
    • いびきを検知したら、OSC経由でVRChatのマイクを自動でOFFにします。
  • リアルタイム分析表示:
    • 「今、どんな音を拾ってるんだろう?」というのが波形やスペクトラムで視覚的に分かります。
  • 柔軟な感度設定:
    • 人によっていびきの音も環境違うため、UIから感度を細かく調整して、自分専用にカスタマイズできます。

技術スタック

このアプリは、以下の技術を組み合わせて作っています。

  • プログラミング言語: Python 3.11
  • GUIフレームワーク: CustomTkinter
  • 音声処理・分析:
    • sounddevice: マイクからリアルタイムに音を入力
    • Librosa: 音声データから特徴を抽出するライブラリ
    • NumPy: 高速な計算処理
    • SciPy: フィルター処理など
  • VRChat連携:
    • python-osc: VRChatと通信するためのOSCメッセージを送受信
  • パッケージング: PyInstaller

なぜAI(機械学習)じゃないの? あえての「ルールベース」

「最近流行りのAI(機械学習)を使えばいいのでは?」と思う方もいるかもしれません。
実際、僕も最初は検討しました。

でも、最終的に「ルールベース」を選びました。

  • 学習データ、どうやって集めるの問題:

    • AIモデルを作るには、「これは、いびき」「これは、いびきじゃない」というラベルが付いた、大量の音声データが必要です[1]
    • 専門機関は睡眠ポリグラフのような機材でデータを集めますが、個人でこれをやるのはほぼ不可能です。
  • 判定状態が分かることの重要性:

    • ルールベースの一番のメリットは、その分かりやすさです。
    • 現在の判定状態がわかることで、ユーザー自身がUIの表示を見ながら「自分の環境だと、この設定を少し上げよう」といった調整ができるからです。
  • なるべくリソースを食いたくない:

    • VRChatをしながら裏で動かすツールなので、なるべく軽く、安定して動作することが大切です。ルールベースは計算がシンプルなので、その点でも安心なのかなと。

もちろん、「人によるいびきの違い」や「環境ノイズ」への対応はルールベースの苦手なところ。でもそこは、SnoreGuardではユーザーが細かく設定を調整できるUIでカバーすることでごまかしています。

ぶっちゃけ、AI関連の勉強はしてこなかったのもあり知識がなさ過ぎて断念したのがでかいです...

実装について

分析のステップ

  1. フィルタリング:

    • まず、マイクから入ってきた音をフィルターにかけ、いびきの主な成分が含まれる 80Hz〜1600Hz の帯域だけを取り出します。

    • 研究によると、いびきの音は1kHz以下に集中していることが多い[2]一方で、病的なものだと1kHzを超える成分も重要になる[3]とのこと。なので、ちょっと広めに範囲をとって、大事な音を取りこぼさないようにしています。

    self.sos_filter = butter(
        N=5, Wn=[80, 1600], btype="bandpass", fs=self.sample_rate, output="sos"
    )
    
  2. 音の特徴量抽出:
    次に、音声分析ライブラリ librosa を使って、音の性質を数値化します。

    • エネルギー (RMS):

      • シンプルに「音の大きさ」です。まずはこれで、ただの呼吸音より大きい音を候補にします。
    • 基本周波数 (F0):

      • 「音の高さ」です。
      • 研究報告で、一般的な「振動型いびき」の基本周波数は150Hz以下[4]とされているのを参考に、70Hz〜150Hz の範囲で安定した高さを持つ音を「いびきっぽい音」としています。
    • スペクトル重心:

      • 「音色の明るさ」を示す指標です。
      • 気道が狭まって出るようないびきほど、この値が低くなる(こもった音になる)傾向がある[5]そうなので、これも判断材料に加えています。
    • ゼロ交差率 (ZCR):

      • 音の波形がプラスとマイナスをどのくらいの頻度で横切るかを示す値です。
      • 突発的なノイズと、いびきのように構造を持つ音を見分けるのに役立つ指標とされています[6]
  3. 持続時間の検証:

  • 咳のような一瞬の音や、エアコンのような鳴りっぱなしの音を「いびき」と間違えないように、音の長さをチェックします。
  • 「いびき候補」の長さが200ms〜3500msの範囲にあるかを確認しています。これも、実際のいびき検出研究で使われている手法を参考にしています[7]
  1. 周期性の検証:
  • いびきの最大の特徴は、呼吸にあわせて「周期的」に発生することです。
  • 特に「振動型いびき」は一定のリズムを保ちます[4:1]。そこで、「いびき候補」が一定時間内(例: 45秒)に一定回数以上(例: 4回)現れたかを最終チェックします。これにより、単発の物音を誤検出するのを防ぎ、最後の砦として機能します。

これらの審査をすべてクリアした音だけを、「いびき」と認定し、VRChatにミュート信号を送ります。

VRChatとの連携 (OSC)

  • VRChatとの連携には、OSC という仕組みを使っています。
  • これは、アプリや機材間で音楽や制御データをやり取りするためのプロトコルで、VRChatも対応しています。
  • いびきを検出すると、OSCを使って/input/Voice0 -> 1 -> 0 の順に値を送ることでミューつ状態が切り替えられます。(ミュート状態はとれないため以下の実装で補助)
  • OSCQueryを使って、ユーザーがもともとミュートにしていたかどうかを管理し、ただしくミュートされるように管理しています。

まとめ

いつか、MLモデル自作して学習ベースでの分析してみたいです...

最後までお読みいただき、ありがとうございました! この記事が、Pythonでの音声処理やVRChat連携ツールの開発に興味がある方の、何かのヒントになれば嬉しいです。

研究を参考にしてますが専門家ではないので...

参考文献

脚注
  1. Accuracy of Smartphone-Mediated Snore Detection in a Simulated Real-World Setting: Algorithm Development and Validation. (2025). JMIR Formative. https://formative.jmir.org/2025/1/e67861/ ↩︎

  2. 原 浩貴, 村上 直子, 山下 裕司 (2003). 「周波数分布から見たいびき音の音響解析」. 口腔・咽頭科, 15(2), 245-252. https://www.jstage.jst.go.jp/article/stomatopharyngology1989/15/2/15_2_245/_pdf/-char/ja ↩︎

  3. Snoring Grades. (2023). News-Medical. https://www.news-medical.net/health/Snoring-Grades.aspx ↩︎

  4. KAKEN. (2014). 「口腔内装置がいびきの音響と気道形態に与える影響の解明」研究成果報告書 (課題番号: 25861951). https://kaken.nii.ac.jp/ja/grant/KAKENHI-PROJECT-25861951/ ↩︎ ↩︎

  5. Saha, S., Moussavi, Z., Hadi, P., Bradley, T. D., & Yadollahi, A. (2018). "Effects of increased pharyngeal tissue mass due to fluid accumulation in the neck on the acoustic features of snoring sounds in men". Journal of Clinical Sleep Medicine, 14(10), 1653–1660. https://pmc.ncbi.nlm.nih.gov/articles/PMC6175800/#:~:text=Current%20Knowledge%2FStudy%20Rationale%3A%20Increased,pharyngeal%20tissue%20and%20induce%20snoring. ↩︎

  6. Chen, F., Wu, H., Liu, H., Li, S., & Wang, Z. (2021). "Automatic classification of excitation location of snoring sounds". Laryngoscope Investigative Otolaryngology, 6(4), 830-838. https://pmc.ncbi.nlm.nih.gov/articles/PMC8320490/ ↩︎

  7. Dafna, E., Tarasiuk, A., & Zigel, Y. (2011). "Automatic detection of snoring events using Gaussian Mixture Models". Proceedings of the Annual Conference of the International Speech Communication Association (INTERSPEECH). https://www.isca-archive.org/maveba_2011/dafna11_maveba.pdf ↩︎

Discussion