Framework de áudio de código aberto para Rust
Testado, não prometido.
O Manguebyte serve para construir plugins e aplicativos de áudio em Rust: DSP e instrumentos, medição, MIDI, arquivos, dispositivos, editores e hospedagem de plugins, e exportação nativa para CLAP, VST 3 e LV2 com uma linha cada. A meta é ser para o Rust o que o JUCE é para o C++, e depois ir além. Cada afirmação deste site leva ao teste que a prova.
Projeto jovem. A API vai mudar antes da versão 1.0. Os editores de plugin abrem em janelas Win32 e são testados no CI, mas ninguém abriu um num host à mão ainda. Veja o que falta.
Verde em todo commit
São testes e resultados de validadores reais, não uma montagem. Todos passaram no CI do commit c5835bf. Cada linha leva ao código.
cargo test --workspace
- pluginautomation_
lands_ okon_ its_ exact_ frame_ and_ updates_ the_ parameter - manguebytethe_
song_ okis_ the_ same_ whatever_ the_ block_ size - dspprocessors_
do_ oknot_ use_ the_ heap - pluginchanges_
made_ okoutside_ the_ host_ reach_ the_ plugin_ as_ events - dspexpression_
and_ okmodulation_ reach_ one_ note_ and_ parameters_ reach_ all - paramsstate_
from_ okanother_ version_ loads_ as_ far_ as_ it_ can - clapnumbers_
too_ oksmall_ to_ hear_ are_ zero_ while_ the_ plugin_ runs_ and_ only_ then - hostthe_
hosted_ okplugin_ sounds_ exactly_ as_ the_ plugin_ does_ alone - analysiscases_
1_ okand_ 2_ a_ steady_ tone_ reads_ its_ level_ on_ all_ three_ scales
01
Quatro coisas que ele prova a cada commit
Igualar o JUCE é a linha de base. Estes são pontos em que o Manguebyte já faz algo que o JUCE 9.0.4 não faz, cada um sustentado por um teste que roda no CI. A lista completa tem quinze, com a fonte de tudo o que se diz sobre o JUCE e o limite de cada afirmação.
-
A automação cai na amostra exata
Cada mudança de parâmetro chega com o frame em que cai e é aplicada nesse frame: no harness de testes, pelo CLAP e pelo VST 3, em que todos os pontos de todas as filas de automação são entregues.
- No JUCE 9.0.4
- O processador lê cada parâmetro uma vez por bloco.
- Limite
- Cabe ao processador usar ou não esse tempo. Ler um valor uma vez por bloco continua válido, e custa menos.
Prova
-
O mesmo som em qualquer tamanho de bloco
Uma música renderizada com seis padrões de bloco, de 64 frames constantes a um irregular
1, 511, 7, 300, 64, 2, 129, tem de sair idêntica bit a bit. Na primeira vez em que rodou, o teste falhou e revelou um bug de verdade.- No JUCE 9.0.4
- Se o som depende ou não do buffer do host fica por conta de cada plugin.
- Limite
- Cobre o que segue os eventos. Um valor lido uma vez por bloco muda nas bordas do bloco, por definição.
Prova
-
Sem heap na thread de áudio, ou o CI falha
Os testes trocam o alocador global por um que conta. Se algum processador, ou o wrapper CLAP, alocar ou liberar memória durante o processamento, o build fica vermelho. Isso já pegou um mutex que aloca no macOS.
- No JUCE 9.0.4
- A segurança em tempo real é uma regra da documentação.
- Limite
- É um teste que roda, não uma prova em tempo de compilação. Pega uso do heap nos caminhos que os testes exercitam.
Prova
-
CLAP e VST 3 com uma linha cada, conferidos pelos próprios validadores
export_clap!eexport_vst3!transformam o mesmo plugin nos dois formatos. O CI roda o validador do projeto CLAP e o da Steinberg num instrumento e num efeito; os 537 testes de VST 3 passam em Windows, Linux e macOS. Os dois também foram testados à mão no REAPER, eexport_lv2!acrescenta um terceiro formato.- No JUCE 9.0.4
- A exportação para CLAP não existe de forma nativa.
- Limite
- Os editores são testados no CI, ainda não foram abertos num host à mão. O LV2 é novo: o lilv o carrega no CI, nenhum host o rodou ainda. Sem AU nem AAX.
Prova
02
Um plugin inteiro, e depois uma linha por formato
Este é o efeito de exemplo do repositório: um ducker com sidechain. Ele se descreve, divide cada bloco nos seus eventos e é exportado duas vezes. Nada do código abaixo foi escrito para esta página.
Uma descrição só
INFOeLAYOUTsão constantes. A mesma descrição vira o descritor CLAP, a classe VST 3, cujo id é igual em todas as plataformas, e os arquivos Turtle do plugin LV2.Eventos no seu frame
split_at_eventsrenderiza até cada evento, aplica-o e segue em frente, sem copiar nem alocar. Essa chamada é tudo o que o plugin faz para ter automação com precisão de amostra.Três formatos, três linhas
As macros são a integração inteira, e
editorentrega aos wrappers o editor do plugin. Ocargo manguegera depois um pacote.clap, um.vst3e um.lv2no layout de cada sistema.
impl Plugin for Duck {
const INFO: PluginInfo = PluginInfo {
id: "org.manguebyte.duck",
name: "Mangue Duck",
vendor: "Manguebyte",
version: env!("CARGO_PKG_VERSION"),
description: "A sidechain ducker, as an example of the Manguebyte framework",
kind: PluginKind::Effect,
};
const LAYOUT: AudioLayout = AudioLayout {
inputs: 2,
outputs: 2,
sidechain: 2,
};
type Params = DuckParams;
// ... new, params and prepare are left out here
fn process(&mut self, buffer: &mut AudioBuffer<f32>, context: &ProcessContext<'_, f32>) {
self.cursor = 0;
let sidechain = context.sidechain;
split_at_events(self, buffer, context.events, Self::handle, |duck, piece| {
duck.render(piece, sidechain)
});
self.publish_reduction();
}
// ... reset
fn editor(&self) -> Option<Box<dyn EditorSpec>> {
Some(Box::new(self.editor_spec()))
}
}
manguebyte::clap::export_clap!(Duck);
manguebyte::vst3::export_vst3!(Duck);
manguebyte::lv2::export_lv2!(Duck);
c5835bf. As linhas que começam com // ... marcam o que ficou de fora.E um teste dele, sem host
Harness toca áudio, um sidechain e automação no plugin dentro de um teste unitário comum. Este confere que uma mudança de profundidade cai no frame 1.000 do bloco, e não um frame antes.
#[test]
fn automation_lands_on_its_frame_with_audio_running_through() {
let mut harness = Harness::<Duck>::new(RATE, 256);
let input = steady(1.0, 24_000);
let loud = steady(1.0, 24_000);
// Let the follower settle, then ask for a different depth on one
// particular frame in the middle of a block.
harness.process_with_sidechain(&input, &loud);
harness.automate(24_000 + 1_000, "depth", 24.0);
let output = harness.process_with_sidechain(&input, &loud);
let before = db_to_gain(-12.0) as f32;
let after = db_to_gain(-24.0) as f32;
assert!((output.channel(0)[999] - before).abs() < 1e-4);
assert!((output.channel(0)[1_000] - after).abs() < 1e-4);
}
c5835bf, como está no arquivo.03
O que já existe
Vinte e três crates que funcionam juntos, cada um utilizável sozinho, um deles uma ferramenta de linha de comando. O manguebyte-core não tem nenhuma dependência.
-
Núcleo
Os tipos sobre os quais todo o resto é construído. Este crate não tem nenhuma dependência.
-
Processamento de sinal
Uma tupla de processadores é um processador: a cadeia é resolvida em tempo de compilação, sem chamadas virtuais e sem alocação.
-
Instrumentos
Vozes prontas para tocar, cada uma com presets, medidas em afinação, decaimento, velocidade e acento, e todas na mesma loudness.
-
Medição e análise
Medidores que rodam na thread de áudio e que qualquer thread lê sem esperar.
-
Grafo de processamento
Um grafo que é religado enquanto toca.
-
Parâmetros
Parâmetros são atômicos dentro de uma struct. Não existem listeners.
-
Plugins
Escreva o plugin uma vez. Exporte como CLAP, VST 3 e LV2 com uma linha cada, rode como aplicativo e teste sem host.
manguebyte-pluginmanguebyte-clapmanguebyte-vst3manguebyte-lv2manguebyte-standalone -
Editores de plugin
Editores desenhados na CPU e abertos numa janela filha da janela do host, por enquanto no Win32. Testados no CI; ninguém abriu um num host à mão ainda.
manguebyte-gfxmanguebyte-uimanguebyte-windowmanguebyte-gui -
Hospedagem de plugins
Carregue plugins feitos por qualquer pessoa e rode-os como processadores.
-
Sampler
Um player de SFZ, aberto para que qualquer programa toque os instrumentos que receber.
-
No navegador
Um motor para o AudioWorklet de um navegador. Testado nativamente e no Node.js, ainda não na thread de áudio de um navegador sob carga.
-
MIDI
MIDI 1.0 e 2.0, com o tempo preservado até a amostra.
-
Arquivos de áudio
Leia e grave arquivos inteiros ou bloco a bloco, do disco até a thread de áudio.
-
Open Sound Control
Mensagens de controladores e de programas de live coding, no frame que elas pedem.
-
Dispositivos
Placas de som e portas MIDI.
-
Ferramenta de linha de comando
De uma pasta vazia a um plugin instalado.
04
Onde o JUCE está à frente
O JUCE tem mais de vinte anos de uso em produção, e muito mais abrangência. Hoje ele tem, e o Manguebyte não:
- um toolkit de interface gráfica completo, com janelas de editor de plugin em todos os sistemas e formatos (os editores do Manguebyte só têm janelas no Win32, e nenhum foi aberto num host à mão ainda);
- os formatos de plugin Audio Unit e AAX;
- hospedagem de plugins AU e LV2, varredura de plugins e os editores dos plugins hospedados (o Manguebyte hospeda plugins CLAP e VST 3, sem os editores);
- mais blocos de DSP, e mais formatos de arquivo;
- iOS e Android;
- documentação, tutoriais e uma comunidade grande.
O roadmap diz o que existe e em que ordem essa distância está sendo fechada.
05
O ecossistema Manguebyte
Mais dois projetos do Recife crescem do mesmo mangue, feitos para rodar sobre o Manguebyte.
-

Este framework
Manguebyte
O framework de áudio de código aberto para Rust, sob MIT ou Apache-2.0. O Aratu já toca sobre o seu motor para o navegador; o Parabolic será construído sobre ele.
-

Em desenvolvimento
Aratu
Uma linguagem de live coding que se lê como música: compassos, tempos e figuras em primeiro lugar, em português, espanhol e inglês. O editor roda no navegador e toca sobre o Manguebyte.
-
Planejado
Parabolic
Uma ferramenta para músicos gravarem os próprios instrumentos e os transformarem em plugins e samplers sem escrever código.
06
Caranguejos com cérebro
O nome vem do Recife, a cidade do Nordeste do Brasil onde este projeto nasceu. O Recife foi construído sobre manguezais.
No começo dos anos 1990, um grupo de músicos da cidade respondeu à crise com um manifesto, Caranguejos com Cérebro: ligar as raízes ricas e lamacentas da cultura da região à rede global de ideias. A imagem que escolheram foi uma antena parabólica fincada na lama do mangue.
Comece com uma dependência
O Manguebyte ainda não está no crates.io. Dependa dele direto do Git:
[dependencies]
manguebyte = { git = "https://github.com/alessonqueirozdev-hub/manguebyte" }
c5835bf, como está no arquivo.