sox
サウンドカードのパイプ入力を開いたままにし、パイプに音がある場合にのみプレーヤーコマンドを実行しようとします(パイプを殺したりファイルを使用せずに)。
これはsox silence 1 0.1 5% -1 0.1 5%
forファイルを使用して簡単に達成できますが、パイプ出力に使用すると機能しません。
これはsox
私が使用するロギングコマンドです。
/bin/sox -V2 -q \
-r 48000 -b 16 -c 2 -t alsa hw:CARD=sndrpihifiberry,DEV=0 \
-t wav -r 44100 -b 16 -c 2 - \
silence 1 0.1 0.1% -1 2 0.5% \
> $streamFile &
パイプに音がある場合にのみ、プレーヤーをパイプに接続または切断したいと思います。それは次のとおりです。
while [ true ]; do
until [ WAIT FOR SOUND ]; do
TEST FOR SOUND IN THE PIPE
done
echo "Sound Detected starting @ $(date)" >> $log
/usr/bin/player < $streamFile &
PLAYERpid=$!
until [ WAIT FOR SILENCE ]; do
TEST FOR SILENCE IN THE PIPE
done
kill $PLAYERpid
echo "Silence Detected killing PLAYER @ $(date)" >> $log
done
どんなアイデアがありますか?
答え1
ダーティハッキングで十分です..
私はMarcusの反応を尊重しますが、ダーティハッキングが十分であればこれを試してみることができます。
指示:
- PulseAudioまたはPipeWireが必要(pulseaudio utilsのインストール)
- 無音検出にはffmpegが必要です。
- プレーヤーが再生を開始する前に、サウンドの小さな部分が失われます。
- オーディオの途中で静かな時間中にプレーヤーが死ぬのを防ぐために、サイレント検出に少し調整が必要な場合があります。
1.オーディオ検出
ここでは実際に素晴らしい信号処理を行う必要はありません。サウンドデバイスの低品質キャプチャを録音し、grepに直接転送して存在するかどうかを確認します。何もないそこに...
#!/bin/bash
# Get your PulseAudio source monitor (edit regex to suit you)
pulse_monitor=$(pactl list short sources | awk '$1 = /alsa.*monitor/ {print $2}')
function wait_for_audio() {
parec --rate 1000 -d $pulse_monitor 2>/dev/null \
| LC_ALL=C fgrep -qm 1 .
}
while [ true ]; do
wait_for_audio
echo "Sound Detected starting @ $(date)" >> $log
/usr/bin/player < $streamFile &
PLAYERpid=$!
...
done
データの最初のバイトが通過するとすぐに、fgrepがパイプを終了するため、待ち時間は非常に短くなります。その時点から、プレイヤーは明らかに敗北します。一部オーディオですがテストでは許容できました。これは簡単な部分です。
2. 沈黙検知
パイプが「何か」を検出したときにパイプを終了するのではなく、「何も検出できないのを待つ」ので、これは少し難しいです。ここではgrepは使用できません。サイレントを検出する1つの方法は、ffmpeg
設定可能なサイレント検出フィルタを使用することです。ただし、パイプラインにffmpegを追加すると、何かが検出されたparec | ffmpeg | fgrep -m1
ときにusingが終了しないため、状況が複雑になりますfgrep -m1
。ご覧のとおり、シャットダウンparec
後はsigpipeで終了しますが、そうではなく、bashはすべてのコマンドが完了するまでパイプから返されません。したがって、パイプの代わりにプロセス置換を使用します。さらに、ffmpegはノイズが非常に多く、無音検出がstdoutの代わりにstderrに出力されるため、ffmpegのstderrとstdoutも交換する必要があります。fgrep
ffmpeg
detect_silence() {
# By default, exit after detecting 2 seconds of continuous silence
SECONDS=${1:-2}
LC_ALL=C fgrep -m 1 silence_start \
<(parec \
--rate 1000 \
--raw \
-d ${pulse_monitor} 2>/dev/null \
| ffmpeg \
-hide_banner \
-f s8 \
-ar 1k \
-ac 2 \
-i pipe: \
-af silencedetect=noise=-50dB:d=${SECONDS} \
-f null - \
3>&1 1>&2 2>&3)
}
CPUオーバーヘッド
オーディオ検出<0.3%
オーディオ検出のオーバーヘッドが非常に低いです。品質には興味がなく、元のデータのほんの一部だけが欲しいので、1khzの速度でオーディオをサンプリングしています。 with(bareより約1400%速い)fgrep
を使用してオーバーヘッドを減らします。私のRaspberry Pi 4では、pulseaudio CPUは実行後最初の数秒間約0.3%で動作します。それ以来、ほぼゼロに落ちた。LC_ALL=C
grep
無音検出 ~1% CPU
ffmpegを実行するときにRaspberry Pi 4 CPUの約1%を使用するため、無音検出のオーバーヘッドが少し高くなります。
私のヒントを使ってコマンドを完了してください。
#!/bin/bash
# Get your PulseAudio source monitor (edit regex to suit you)
pulse_monitor=$(pactl list short sources | awk '$1 = /alsa.*monitor/ {print $2}')
function wait_for_audio() {
# sample audio at 1khz and exit as soon as data is detected
parec --rate 1000 -d $pulse_monitor 2>/dev/null \
| LC_ALL=C fgrep -qm 1 .
}
detect_silence() {
# By default, exit after detecting 2 seconds of continuous silence
SECONDS=${1:-2}
LC_ALL=C fgrep -m 1 silence_start \
<(parec \
--rate 1000 \
--raw \
-d ${pulse_monitor} 2>/dev/null \
| ffmpeg \
-hide_banner \
-f s8 \
-ar 1k \
-ac 2 \
-i pipe: \
-af silencedetect=noise=-50dB:d=${SECONDS} \
-f null - \
3>&1 1>&2 2>&3)
}
while [ true ]; do
wait_for_audio
echo "Sound Detected starting @ $(date)" >> $log
/usr/bin/player < $streamFile &
PLAYERpid=$!
detect_silence 2
echo "Silence Detected starting @ $(date -d "2 seconds ago")" >> $log
kill $PLAYERpid
"Silence Detected killing PLAYER @ $(date)" >> $log
done
答え2
正直なところ、シェルスクリプトでは信号処理を試みてはいけません。これは、一連のバイナリデータに対して定期的に算術を実行することに依存します。このループを毎秒数百回実行しても、コンピュータは困難になり、継続的な信号処理を実行できます。
申し訳ありません。動作しません。
非常に良いフレームワークの1つを使用すると簡単にこれを行うことができますが、上記の理由でシェルスクリプトを提供するフレームワークはありません。大丈夫です。シェルスクリプトを必要とせずに動作する必要があります!
私はあなたがそれを試すことをお勧めしますGNUラジオ。ソフトウェア定義のラジオに焦点を当てていますが、単純なオーディオ処理ツールキットを設計するのはかなり良いです。迅速に構築できる場合は、以下のように効果がありますが、「しきい値」の高い(開始)値と低い(停止)の値を調整する必要があるかもしれません。
上記は単なる例です。入力音量が最大可能値の10%を超えるとすぐに音が鳴り始め、5%未満に低下すると停止します。
信号処理フローチャートを設計するために使用されるツールであるGNU Radio Companionの「作成」ボタンをクリックすると、実行可能なスクリプトが生成されます。 bashスクリプトではなくPythonですが、システムには何の影響もありません(これはファイルの先頭#!/usr/bin/env python
にある行です。システムにスクリプトの実行方法を伝えます。#!/bin/bash
これを使用してビルドできるものには実際の制限はありません。オーディオファイルを読み取ることができるソースがあり、信号を処理するためのより多くの方法があり、GNU Radioが基本的に実行できない作業を実行する必要がある場合は、Pythonでブロックを作成するのは実際には難しいことではありません!