Uma biblioteca de conversão de taxa de amostragem de áudio para ferrugem.
Esta biblioteca fornece reamostradores para processar áudio em pedaços.
A proporção entre as taxas de amostragem de entrada e saída é completamente livre. Estão disponíveis implementações que aceitam uma entrada de comprimento fixo ao retornar uma saída de comprimento variável e vice -versa.
O Rubato pode ser usado em aplicativos em tempo real, sem qualquer alocação durante o processamento, pré -alocando um [resompler] e usando seus métodos input_buffer_allocate e output_buffer_allocate antes de iniciar o processamento. O recurso de log deve ser desativado para uso em tempo real (é desativado por padrão).
Os dados de entrada e saída são armazenados em um formato não inter-interlutado.
Os dados de entrada e saída são armazenados como fatias de referências, &[AsRef<[f32]>]
ou &[AsRef<[f64]>]
. As referências internas ( AsRef<[f32]>
ou AsRef<[f64]>
) mantêm os valores da amostra para um canal cada.
Como os vetores normais implementam o traço AsRef
, Vec<Vec<f32>>
e Vec<Vec<f64>>
podem ser usados para entrada e saída.
Os reamostradores assíncronos estão disponíveis com e sem filtros anti-aliasing.
A reamostragem com anti-aliasing é baseada na interpolação limitada por banda usando filtros de interpolação SINC. As amostras de interpolação SINC por um fator ajustável e, em seguida, os novos pontos de amostra são calculados interpolando entre esses pontos. A taxa de reamostragem pode ser atualizada a qualquer momento.
A reamostragem sem aliasing omite a interpolação sincy pesada da CPU. Isso funciona muito mais rápido, mas produz um resultado de menor qualidade.
A reamostragem síncrona é implementada via FFT. Os dados são FFT: ED, o espectro modificado e, em seguida, FFT Inverse: ED para obter os dados reamostrados. Esse tipo de reamostrador é consideravelmente mais rápido, mas não suporta a alteração da taxa de reamostragem.
Os reamostradores fornecidos por esta biblioteca destinam -se a processar áudio em pedaços. O tamanho ideal do pedaço é determinado pelo aplicativo, mas provavelmente acabará em algum lugar entre algumas centenas a alguns milhares de quadros. Isso dá um bom comprometimento entre a eficiência e o uso da memória.
O Rubato é adequado para aplicações em tempo real ao usar o método Resampler::process_into_buffer()
. Isso armazena a saída em um buffer de saída pré-alocado e não executa alocações ou outras operações que possam bloquear o encadeamento.
Um processo simples sugerido para reamostragem um clipe de áudio de comprimento conhecido a uma nova taxa de amostragem é o seguinte. Aqui é assumido que os dados de origem são armazenados em um VEC, ou alguma outra estrutura que suporta a leitura do número arbitrário de quadros por vez. Por simplicidade, a saída é armazenada em um buffer temporário durante a reamostragem e copiado para o destino depois.
Preparativos:
Resampler::output_delay()
para saber quantos quadros de atraso o reamostrador fornece. Armazene o número como delay
.new_length = original_length * new_rate / original_rate
.Agora é hora de processar a maior parte do clipe por chamadas de procesação repetidas. Laço:
Resampler::input_frames_next()
para saber quantos quadros o reamosne precisa.Resampler::process()
ou Resampler::process_into_buffer()
.O próximo passo é processar os últimos quadros restantes.
Resampler::process_partial()
ou Resampler::process_partial_into_buffer()
. Nesse ponto, todos os quadros foram enviados para o reamostrador, mas, devido ao atraso através do reamostrador, ele ainda pode ter alguns quadros em seus buffers internos. Quando todos os quadros desejados foram gerados, o comprimento do buffer de saída temporário deve ser pelo menos new_length + delay
. Se não for esse o caso, ligue para Resampler::process_partial()
ou Resampler::process_partial_into_buffer()
com None
como entrada e anexa a saída ao buffer de saída temporário. Se necessário, repita até que o comprimento seja suficiente.
Por fim, copie os dados do buffer de saída temporário para o destino desejado. Pule os primeiros quadros delay
e copie os quadros new_length
.
Se houver mais de um clipe para resampar e para as mesmas taxas de amostra, o mesmo reamostrador deve ser reutilizado. Criar um novo reamostrador é uma tarefa cara e deve ser evitado, se possível. Inicie o procedimento desde o início, mas, em vez de criar um novo reamostrador, ligue para Resampler::reset()
no existente para prepará -lo para um novo trabalho.
Ao reamprar um fluxo, o processo é normalmente realizado em tempo real e a entrada da saída é uma API que fornece ou consome quadros a uma determinada taxa.
APIs de áudio como o Coreaudio no macOS, ou a caixa CPAL da Cross Platform, geralmente usam funções de retorno de chamada para troca de dados.
Um completo
Ao capturar áudio a partir deles, o aplicativo passa uma função para a API de áudio. A API chama essa função periodicamente, com um ponteiro para um buffer de dados que contém novos quadros de áudio. O tamanho do buffer de dados geralmente é o mesmo em todas as chamadas, mas isso varia entre as APIs. É importante que a função não bloqueie, pois isso bloqueia algum loop interno da API e causaria perda de alguns dados de áudio. É recomendável manter a luz da função de retorno de chamada. Idealmente, ele deve ler os dados de áudio fornecidos do buffer fornecido pela API e, opcionalmente, executar algum processamento de luz, como a conversão de formato de amostra. Nenhum processamento pesado, como reamostragem, deve ser realizado aqui. Em seguida, deve armazenar os dados de áudio em um buffer compartilhado. O buffer pode ser um Arc<Mutex<VecDeque<T>>>
, ou algo mais avançado, como o ringbuf.
Um loop separado, executando no encadeamento principal ou separado, deve ler esse buffer, reampler e salvar no arquivo. Se a API de áudio fornecer um tamanho de buffer fixo, esse número de quadros é uma boa opção para o tamanho do pedaço de reamostrador. Se o tamanho variar, o buffer compartilhado pode ser usado para adaptar os tamanhos de bloco da API de áudio e do reamostrador. Um bom ponto de partida para o tamanho do pedaço de reamostrador é usar um valor "fácil" próximo ao tamanho médio do chunk da API de áudio. Verifique se o buffer compartilhado é grande o suficiente para não ficar cheio, caso o loop seja bloqueado à espera, por exemplo, para acesso ao disco.
O loop deve seguir um processo semelhante à reamostragem de um clipe, mas a entrada agora é o buffer compartilhado. O loop precisa esperar que o número necessário de quadros fique disponível no buffer, antes de lê -los e passá -los para o reamostrador.
Também seria apropriado omitir o buffer de saída temporário e escrever a saída diretamente no destino. O Crente Hound é uma escolha popular para ler e escrever formatos de áudio não compactados.
O reamostrador assíncrono suporta SIMD no x86_64 e no AARCH64. Os recursos SIMD da CPU são determinados em tempo de execução. Se nenhum conjunto de instruções SIMD suportado estiver disponível, ele voltará a uma implementação escalar.
No x86_64, ele tentará usar o AVX. Se o AVX não estiver disponível, tentará o SSE3.
No AARCH64 (braço de 64 bits), ele usará neon se disponível.
Os reamostradores síncronos se beneficiam do suporte SIMD da biblioteca Rustfft.
fft_resampler
: Ative os reamostradores síncronos baseados em FFTEste recurso é ativado por padrão. Desative -o se os reamostradores FFT não forem necessários, para economizar tempo de compilação e reduzir o tamanho binário resultante.
log
: Ativar log Esse recurso permite o log através da caixa log
. Isso se destina a fins de depuração. Observe que a saída de logs aloca um [std :: string :: string] e a maioria das implementações de log envolve várias outras chamadas do sistema. Essas chamadas podem levar algum tempo (imprevisível) para retornar, durante o qual o aplicativo está bloqueado. Isso significa que o registro deve ser evitado se estiver usando esta biblioteca em um aplicativo em tempo real.
O recurso log
pode ser ativado ao executar os testes, o que pode ser muito útil ao depurar. O nível de log pode ser definido através da variável de ambiente RUST_LOG
.
Exemplo:
RUST_LOG=trace cargo test --features log
Remamale um único pedaço de um arquivo de áudio fictício de 44100 a 48000 Hz. Consulte também o exemplo "process_f64" que pode ser usado para processar um arquivo do disco.
use rubato :: { Resampler , SincFixedIn , SincInterpolationType , SincInterpolationParameters , WindowFunction } ;
let params = SincInterpolationParameters {
sinc_len : 256 ,
f_cutoff : 0.95 ,
interpolation : SincInterpolationType :: Linear ,
oversampling_factor : 256 ,
window : WindowFunction :: BlackmanHarris2 ,
} ;
let mut resampler = SincFixedIn :: < f64 > :: new (
48000 as f64 / 44100 as f64 ,
2.0 ,
params ,
1024 ,
2 ,
) . unwrap ( ) ;
let waves_in = vec ! [ vec! [ 0.0f64 ; 1024 ] ; 2 ] ;
let waves_out = resampler . process ( & waves_in , None ) . unwrap ( ) ;
O diretório examples
contém alguns aplicativos de amostra para testar os reamostradores. Existem também scripts Python para gerar sinais de teste simples, além de analisar os resultados reamostrados.
Os exemplos leem e escrevem dados de áudio bruto em formato de flutuação de 64 bits. Eles podem ser usados para processar arquivos .wav se os arquivos forem convertidos primeiro no formato certo. Use sox
para converter um .wav em amostras cruas:
sox some_file.wav -e floating-point -b 64 some_file_f64.raw
Após o processamento, o resultado pode ser convertido de volta para o novo .wav. Este exemplos se converte em 16 bits a 44,1 kHz:
sox -e floating-point -b 64 -r 44100 -c 2 resampler_output.raw -e signed-integer -b 16 some_file_resampled.wav
Muitos editores de áudio, por exemplo, Audacity, também podem importar e exportar diretamente as amostras brutas.
A caixa rubato
requer Rustc versão 1.61 ou mais recente.
fft_resampler
.log
.input/output_buffer_allocate()
opcionalmente pré-preenchimento buffers com zeros.Licença: MIT