O Problema

  • Eu tenho uma banda (🍪).
  • Nós gostamos de nos gravar 🌚, áudio e vídeo.
  • Nós temos uma mesa de som velha, com uma interface USB 🎚️.
  • Nós temos um netbook velho de um núcleo, 32bits 💻.
  • Nós queremos eventualmente gravar multipista com uma interface adicional, ou juntando várias pra fazer mixagens melhores 🎛️.
  • Nós temos celulares pra gravar vídeos 📹.
  • Eu tenho um aplicativo que comanda câmeras de celulares (android, apenas) 📱.
  • Não sabemos se vai funcionar pois o netbook é bem antigo e lento. Sim, já quero inventar antes de testar.

Pois bem. Eu tenho um raspberry pi 3 sobrando 🍓.

Qual é o problema? Nenhum, eu quero inventar alguma coisa 😄.

As idéia

A ideia principal é: Um gravador portátil, simples de usar (pluga a(s) interface(s) e aperta gravar). E por gravar, eu entendo:

  1. Gravar áudio das interfaces
  2. Enviar o comando de gravação para as câmeras

Limitações

Se não me engano, temos ALSA (um sistema de áudio do Linux) por padrão no Raspberry Pi OS. Dá até pra agregar interfaces (pegar várias e transformar em uma interface só), mas também dá pra disparar vários processos do arecord (o programa gravador padrão do ALSA) pra gravar áudio de interfaces diferentes ao mesmo tempo, que parece mais simples.

Bom, o raspberry pi não tem tela, nem pretendo colocar. Botões talvez sejam uma boa ideia, mas, pelo menos inicialmente, vou precisar de mais controle, até porque vou estar explorando, né?.

Se não tem tela, não tem interface gráfica. Daria até pra rodar um Reaper e tentar fazer alguma mágica, mas acho que temos soluções mais simples, pelo menos por enquanto. Provavelmente vou pelo caminho de interface web pra comandar por um celular ou tablet.

E daí vem o nome desse projeto. Normalmente chamamos algo que não tem uma interface direta (nesse caso, uma tela) de headless, ou sem cabeça.

Pra acessar a interface web, eu vou precisar conectar no pi num ambiente potencialmente sem rede, então vou ter que sacrificar o WiFi do Pi pra criar um hot spot onde o controlador vai conectar. Não é muito diferente de como as mesas de som digitais funcionam.

Para as câmeras tem o meu projeto citado acima, mas o mais importante é o áudio. Mais importante ainda é:

Dado um Raspberry Pi 3B com uma interface de áudio conectada, eu consigo conectar diretamente nele via WiFi com um tablet e enviar comandos pra gravar áudio?

Protótipo

Vamos lá.

Tenho algumas coisas pra testar.

  1. Consigo gravar de uma interface de áudio usando arecord?
  2. Consigo gravar de duas interfaces de áudio simultaneamente usando arecord?
  3. Consigo usar um serviço web pra disparar a gravação?
  4. Consigo conectar e enviar os comandos acima diretamente no pi como um hot spot?

Mão na massa

Vamos tentar riscar o primeiro item.

Reinstalei o Pi e pluguei minha interface numa das portas USB. Vamos ver se o ALSA detectou.

Eu sei que existe um comando pra gravar áudio direto da linha de comando, que faz parte da “caixa de ferramentas” do ALSA, chamado arecord.

Bora tentar:

raphaelpaiva@hr:~ $ arecord
Usage: arecord [OPTION]... [FILE]...

-h, --help              help
    --version           print current version
-l, --list-devices      list all soundcards and digital audio devices
-L, --list-pcms         list device names
-D, --device=NAME       select PCM by name
-q, --quiet             quiet mode
-t, --file-type TYPE    file type (voc, wav, raw or au)
-c, --channels=#        channels
-f, --format=FORMAT     sample format (case insensitive)
-r, --rate=#            sample rate
-d, --duration=#        interrupt after # seconds
-s, --samples=#         interrupt after # samples per channel
-M, --mmap              mmap stream
-N, --nonblock          nonblocking mode
-F, --period-time=#     distance between interrupts is # microseconds
-B, --buffer-time=#     buffer duration is # microseconds
    --period-size=#     distance between interrupts is # frames
    --buffer-size=#     buffer duration is # frames
-A, --avail-min=#       min available space for wakeup is # microseconds
-R, --start-delay=#     delay for automatic PCM start is # microseconds
                        (relative to buffer size if <= 0)
-T, --stop-delay=#      delay for automatic PCM stop is # microseconds from xrun
-v, --verbose           show PCM structure and setup (accumulative)
-V, --vumeter=TYPE      enable VU meter (TYPE: mono or stereo)
-I, --separate-channels one file for each channel
-i, --interactive       allow interactive operation from stdin
-m, --chmap=ch1,ch2,..  Give the channel map to override or follow
    --disable-resample  disable automatic rate resample
    --disable-channels  disable automatic channel conversions
    --disable-format    disable automatic format conversions
    --disable-softvol   disable software volume control (softvol)
    --test-position     test ring buffer position
    --test-coef=#       test coefficient for ring buffer position (default 8)
                        expression for validation is: coef * (buffer_size / 2)
    --test-nowait       do not wait for ring buffer - eats whole CPU
    --max-file-time=#   start another output file when the old file has recorded
                        for this many seconds
    --process-id-file   write the process ID here
    --use-strftime      apply the strftime facility to the output file name
    --dump-hw-params    dump hw_params of the device
    --fatal-errors      treat all errors as fatal
Recognized sample formats are: S8 U8 S16_LE S16_BE U16_LE U16_BE S24_LE S24_BE U24_LE U24_BE S32_LE S32_BE U32_LE U32_BE FLOAT_LE FLOAT_BE FLOAT64_LE FLOAT64_BE IEC958_SUBFRAME_LE IEC958_SUBFRAME_BE MU_LAW A_LAW IMA_ADPCM MPEG GSM S20_LE S20_BE U20_LE U20_BE SPECIAL S24_3LE S24_3BE U24_3LE U24_3BE S20_3LE S20_3BE U20_3LE U20_3BE S18_3LE S18_3BE U18_3LE U18_3BE G723_24 G723_24_1B G723_40 G723_40_1B DSD_U8 DSD_U16_LE DSD_U32_LE DSD_U16_BE DSD_U32_BE
Some of these may not be available on selected hardware
The available format shortcuts are:
-f cd (16 bit little endian, 44100, stereo)
-f cdr (16 bit big endian, 44100, stereo)
-f dat (16 bit little endian, 48000, stereo)

Ele me chamou de burro de forma educada.

Usage: arecord [OPTION]... [FILE]... me diz como usar esse comando. Eu tenho que passar pra ele opções (pelo menos uma) ou arquivos (pelo menos um).

Vamos tentar passar um arquivo qualquer, deve ser o arquivo de destino da gravação.

raphaelpaiva@hr:~ $ arecord opa.wav
arecord: main:830: audio open error: No such file or directory

Ok, erro ao abrir o áudio. Soa até meio estranho. Como no Linux tudo é representado por um arquivo, inclusive a minha interface de áudio, eu suspeito que ele não tenha conseguido abrir o dispositivo de áudio. Talvez tenhamos que informar o arecord de qual interface eu quero gravar. Vai que tem mais de uma.

Da saída ali em cima, onde as opções foram listadas, algumas chamaram minha atenção. A primeira delas foi

-l, --list-devices      list all soundcards and digital audio devices

Bora lá tentar passar essa opção então!

raphaelpaiva@hr:~ $ arecord -l
**** List of CAPTURE Hardware Devices ****
card 2: CODEC [USB Audio CODEC], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Opa! Essa saída significa que ele detectou um dispositivo de saída.

Traduzindo:

  • card 2: CODEC [USB Audio CODEC], device 0: USB Audio [USB Audio]
    • Esse dispositivo está na placa número 2 (card 2).
    • O nome dessa placa é CODEC [USB Audio CODEC].
    • O dispositivo de saída é o primeiro dispositivo desta placa (device 0).
    • O nome dele é USB Audio [USB Audio].
  • Subdevices: 1/1
    • Ele tem um sub-dispositivo
  • Subdevice #0: subdevice #0
    • Este sub-dispositivo é o número 0

Entendeu? Eu também não, mas já deu pra sacar que o ALSA faz referência dos dispositivos por números ou por nomes.

Do manual do ALSA, tem uma outra opção interessante:

-L, --list-pcms
        List all PCMs defined

Que diabos é um PCM? É uma sigla pra Pulse-code modulation, ou uma das formas que um computador pode “ouvir”. No contexto do ALSA, PCM é o que vem do seu dispositivo de captura, ou seja, essa opção lista as fontes de áudio disponíveis.

Vou escrever sobre PCM depois, é muito interessante, mas não vale alongar aqui.

raphaelpaiva@hr:~ $ arecord -L
null
    Discard all samples (playback) or generate zero samples (capture)
hw:CARD=CODEC,DEV=0
    USB Audio CODEC, USB Audio
    Direct hardware device without any conversions
plughw:CARD=CODEC,DEV=0
    USB Audio CODEC, USB Audio
    Hardware device with all software conversions
default:CARD=CODEC
    USB Audio CODEC, USB Audio
    Default Audio Device
sysdefault:CARD=CODEC
    USB Audio CODEC, USB Audio
    Default Audio Device
front:CARD=CODEC,DEV=0
    USB Audio CODEC, USB Audio
    Front output / input
dsnoop:CARD=CODEC,DEV=0
    USB Audio CODEC, USB Audio
    Direct sample snooping device

Temos um pouco mais de informação dessa opção do arecord. Duas seções saltam aos olhos:

hw:CARD=CODEC,DEV=0
    USB Audio CODEC, USB Audio
    Direct hardware device without any conversions
plughw:CARD=CODEC,DEV=0
    USB Audio CODEC, USB Audio
    Hardware device with all software conversions

Parece que temos acesso ao dado direto do hardware com o hw: e acesso ao dado tratado com o plughw:. Que diferença isso faz? Sei lá. Vou chutar que podem rolar umas conversões de formato e taxa de amostragem, mas tem uma outra coisa mais importante:

hw:CARD=CODEC,DEV=0 tem muita cara de ser um identificador de dispositivo. CODEC é o nome da placa que vimos na saída do arecord -l e 0 é o número do dispositivo, então hw:CARD=CODEC,DEV=0 deve significar a fonte de áudio direto do hardware que vem da placa CODEC, dispositivo 0. Da mesma forma, plughw:CARD=CODEC,DEV=0 deve significar a mesma fonte de áudio, mas com conversões de software, seja lá o que isso signifique.

A tradução do resto da saída do arecord -L fica como exercício para o leitor 😄.

Uma terceira opção que chamou atenção foi a seguinte:

-D, --device=NAME       select PCM by name

Tá com toda cara que é com essa opção que eu digo qual é a interface que eu quero utilizar. Resta saber se vamos de hw: ou plughw:. Como o plughw: faz conversões, ele parece ser a aposta mais segura.

Vamo lá

raphaelpaiva@hr:~ $ arecord -Dplughw:CARD=CODEC,DEV=0 opa.wav
Recording WAVE 'opa.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono

Parece que tá gravando!

Como eu não sabia parar, meti um ctrl+C mesmo (padrão para abortar programas na linha de comando) e vamos ver no que deu.

Se não apareceu o áudio, ouve aí a alegra do nerdola

Parece até o áudio do Yuri Gagarin com essa qualidade tosca. Tudo bem, com 8 bits de resolução e uma taxa de amostragem de 8kHz não dá pra esperar muita coisa.

Vamos ver se dá pra melhorar isso, mas eu estou curioso pra saber o que vem se eu usar o hw:.

raphaelpaiva@hr:~ $ arecord -Dhw:CARD=CODEC,DEV=0 opa.wav
Recording WAVE 'opa.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono
arecord: set_params:1343: Sample format non available
Available formats:
- S8
- S16_LE

Opa! Eu gosto de erro assim. Que diz o que eu fiz de errado e ainda diz como consertar:

arecord: set_params:1343: Sample format non available
Available formats:
- S8
- S16_LE

Então eu tenho que especificar o formato da amostra. Lá da primeira saída do programa, dá pra ver como e ainda tem algumas opções interessantes pra controlar a qualidade e duração.

-c, --channels=#        channels
-f, --format=FORMAT     sample format (case insensitive)
-r, --rate=#            sample rate
-d, --duration=#        interrupt after # seconds

Vamos mexer só no formato por enquanto, que foi o que ele reclamou.

raphaelpaiva@hr:~ $ arecord -Dhw:CARD=CODEC,DEV=0 -f S16_LE opa.wav
Recording WAVE 'opa.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Mono
Warning: rate is not accurate (requested = 8000Hz, got = 11025Hz)
         please, try the plug plugin

Deu um warning, mas gravou. Vou chorar 😭.

Ouve aí o choro do nerdola.

Reparou que a qualidade parece bem melhor? Esse foi o salto de 8bits/8000Hz pra 16bits/11025Hz. Brabo.

Vou escrever sobre o que esses número significam, mas calma.

Vamos brincar um pouco com os outros parâmetros.

Eu quero gravar um áudio de 5 segundos, 16bits, 44100Hz e usando todos os 2 canais da interface. Vou plugar minha guitarra no segundo canal e bora ver se vai sair fumaça.

arecord -Dhw:CARD=CODEC,DEV=0 -d 5 -f S16_LE -r 44100 -c 2 opa.wav
Recording WAVE 'opa.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo

Ai papai! Emocionado. Ouve aí!.

Conclusão

Dá, hein!

Vimos como gravar áudio de uma interface de áudio via linha de comando usando o ALSA, sistema de som padrão no Raspberry Pi OS.

Na próxima etapa vamos ver se conseguimos gravar de duas interfaces simultaneamente.

Segue o pai!

Dedico esse posto ao nut da minha guitarra que quebrou durante essa gravação. Não coloque si no lugar da mizinha, viu?