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을 사용할 수 없습니다. 침묵을 감지하는 한 가지 방법은 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%로 실행됩니다. 그 이후에는 거의 0으로 떨어졌습니다.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
솔직히 말해서, 쉘 스크립트에서는 신호 처리를 시도해서는 안 됩니다. 이는 일련의 이진 데이터에 대해 정기적으로 산술을 수행하는 데 의존합니다. 이 루프를 초당 수백 번 실행하더라도 컴퓨터는 어려움을 겪게 되며, 이를 통해 지속적인 신호 처리를 수행할 수 있습니다.
죄송합니다. 작동하지 않습니다.
아주 좋은 프레임워크 중 하나를 사용하면 쉽게 이 작업을 수행할 수 있지만 위에서 언급한 이유로 인해 쉘 스크립트를 제공하는 프레임워크는 없습니다. 괜찮습니다. 쉘 스크립트가 필요하지 않고 작동하는 것이 필요합니다!
나는 당신이 그것을 시도하는 것이 좋습니다GNU 라디오. 소프트웨어 정의 라디오에 중점을 두고 있지만 간단한 오디오 처리 툴킷을 설계하는 데는 꽤 좋습니다. 빠르게 구축할 수 있다면 아래 설명된 대로 효과가 있었지만 "임계값" 높은(시작) 값과 낮은(중지) 값을 조정해야 할 수도 있습니다.
위의 내용은 단지 예일 뿐입니다. 입력 볼륨이 최대 가능한 값의 10%를 초과하자마자 소리가 나기 시작하고 5% 미만으로 떨어지면 멈춥니다.
신호 처리 흐름도를 설계하는 데 사용되는 도구인 GNU Radio Companion에서 "생성" 버튼을 클릭하면 실행 가능한 스크립트가 생성됩니다. bash 스크립트가 아니라 Python이지만 시스템에는 아무런 영향이 없습니다( 이것이 바로 #!/usr/bin/env python
파일 시작 부분에 있는 줄입니다: 시스템에 스크립트 실행 방법을 알려줍니다.#!/bin/bash
이를 사용하여 빌드할 수 있는 것에는 실제 제한이 없습니다. 오디오 파일을 읽을 수 있는 소스가 있고, 신호를 처리하는 더 많은 방법이 있으며, GNU Radio가 기본적으로 수행할 수 없는 작업을 수행해야 하는 경우 Python에서 블록을 작성하는 것은 't “사실 별로 어렵지 않아요!