Atualizações de áudio da Web no Chrome 49

Chris wilson
Chris Wilson

O Chrome tem aprimorado de forma consistente e silenciosa o suporte à API Web Audio. No Chrome 49 (Beta a partir de fevereiro de 2016, e esperamos que seja estável em março de 2016), atualizamos vários recursos para rastrear a especificação, além de adicionar um novo nó.

decodeAudioData() agora retorna uma promessa

O método decodeAudioData() em AudioContext agora retorna um Promise, permitindo o processamento de padrões assíncronos com base em promessas. O método decodeAudioData() sempre teve as funções de callback de sucesso e erro como parâmetros:

context.decodeAudioData( arraybufferData, onSuccess, onError);

Mas agora você pode usar o método Promise padrão para lidar com a natureza assíncrona da decodificação de dados de áudio:

context.decodeAudioData( arraybufferData ).then(
        (buffer) => { /* store the buffer */ },
        (reason) => { console.log("decode failed! " + reason) });

Embora em um único exemplo isso pareça mais detalhado, as promessas tornam a programação assíncrona mais fácil e mais consistente. Para compatibilidade, as funções de callback "Success" e "Error" ainda são compatíveis, conforme a especificação.

Off-lineAudioContext agora é compatível com suspend() e resume()

À primeira vista, pode parecer estranho ter suspend() em um OfflineAudioContext. Afinal, suspend() foi adicionado a AudioContext para permitir colocar o hardware de áudio no modo de espera, o que parece inútil em cenários em que você está renderizando em um buffer, que é a finalidade de OfflineAudioContext. No entanto, o objetivo desse recurso é conseguir construir apenas parte de uma "pontuação" por vez, para minimizar o uso da memória. É possível criar mais nós enquanto suspensos no meio de uma renderização.

Como exemplo, a Sonata Moonlight de Beethoven contém cerca de 6.500 notas. Cada "nota" provavelmente é desconstruída para pelo menos alguns nós de gráfico de áudio (por exemplo, um AudioBuffer e um nó de ganho). Se você quer renderizar os sete minutos e meio inteiros em um buffer com OfflineAudioContext, provavelmente não vai querer criar todos esses nós de uma só vez. Em vez disso, é possível criá-los em períodos de tempo:

var context = new OfflineAudioContext(2, length, sampleRate);
scheduleNextBlock();
context.startRendering().then( (buffer) => { /* store the buffer */ } );

function scheduleNextBlock() {
    // create any notes for the next blockSize number of seconds here
    // ...

    // make sure to tell the context to suspend again after this block;
    context.suspend(context.currentTime + blockSize).then( scheduleNextBlock );

    context.resume();
}

Isso permite minimizar o número de nós que precisam ser pré-criados no início da renderização e diminuir as demandas de memória.

IIRFilterNode

A especificação adicionou um nó para audiófilos que querem criar a própria infinite-impulse-response especificado com precisão: o IIRFilterNode. Esse filtro complementa o BiquadFilterNode, mas permite a especificação completa dos parâmetros de resposta do filtro, em vez do AudioParams fácil de usar do BiquadFilterNode para tipo, frequência, Q e similares. O IIRFilterNode permite a especificação precisa de filtros que não podiam ser criados antes, como filtros de ordem única. No entanto, o uso do IIRFilterNode exige um conhecimento profundo de como os filtros IIR funcionam, e eles também não são programáveis como BiquadFilterNodes.

Alterações anteriores

Também quero mencionar algumas melhorias anteriores: no Chrome 48, a automação do nó BiquadFilter começou a ser executada na taxa de áudio. A API não mudou para fazer isso, mas isso significa que o processo de limpeza do filtro terá um som ainda mais suave. Ainda no Chrome 48, adicionamos o encadeamento ao método AudioNode.connect(), retornando o nó a que estamos nos conectando. Isso simplifica a criação de cadeias de nós, como neste exemplo:

sourceNode.connect(gainNode).connect(filterNode).connect(context.destination);

Isso é tudo por enquanto, e continue assim!