Eu sei como tocar a campainha com echo -ne '\a'
(ou, melhor ainda, se você não se importar em contar com um comando externo: tput bel
). No entanto, o que ele realmente faz é enviar algum código especial para a saída; então, se essa saída for um terminal , o terminal interpretará o código e tocará a campainha.
Meu problema é que quero emitir ruídos de aviso de um script em segundo plano, cuja saída não é lida por nenhum terminal. Posso tocar algum .wav
arquivo harmonioso com paplay
ou similar, mas prefiro aquele bip simples e estridente. E gostaria de não depender de programas externos.
Então, perguntas:
- O som da campainha, emitido pelos terminais, é especial de alguma forma (por exemplo, usando um hardware dedicado), ou é um arquivo de som como qualquer outro?
- Como reproduzir esse som?
Depois de estudar o código-fonte do programa
beep
, criei um programa em C mínimo que toca a campainha.Ele usa o alto-falante do PC, que o kernel do Linux disponibiliza como um dispositivo evdev geralmente chamado
/dev/input/by-path/platform-pcspkr-event-spkr
(um link simbólico para um local real).Há um evento para ligar o alto-falante ( ou seja, para começar a produzir som) em uma determinada frequência e outro evento para desligar o alto-falante ( ou seja, para parar o som). Simplesmente enviamos o primeiro evento, dormimos pela duração necessária e enviamos o segundo evento.
Isso requer acesso de gravação ao dispositivo, que pode ser configurado por meio de uma regra udev, o bit setuid para o programa ou executando o programa como root, conforme descrito na documentação do
beep
. Além disso, isso não pode controlar o volume do som. De alguma forma, oxset
programa (do pacote de servidores X) e os emuladores de terminal não possuem essas restrições.Em C
(Para concisão e clareza, o código-fonte acima ignora todas as verificações de segurança (verifique se o arquivo existe, verifique se
open
foi bem-sucedido, verifique se o descritor do arquivo é um dispositivo de caractere, verifique se a frequência e a duração são números inteiros dentro do intervalo permitido, verifique sewrite
for bem-sucedido, verifique se foi bem-nanosleep
sucedido…). Em um aplicativo real, isso deve ser abordado.)Em um script de shell
O programa C acima pode ser usado para observar a forma dos eventos; então, os mesmos eventos podem ser escritos a partir de um script de shell. Infelizmente, o formato binário é provavelmente específico da plataforma. Na minha máquina x86-64 com o kernel Linux 5.2, o evento de som tem a seguinte estrutura:
type
com valorEV_SND
)code
com valorSND_TONE
)value
)Essa estrutura binária pode ser escrita usando Perl com a função
pack
. Inteiros binários também podem ser gerados usando Bash puro , mas isso é mais detalhado.Se o seu script estiver sendo executado como root, você pode simplesmente fazer: