Fórum BASS Library: BASS_ChannelGetData: Visualizações, FFT e PCM! #365739
01/11/2008
0
Olá pessoal!
Recentemente voltei a usar este fórum e vi um tópico meu, que modéstia à parte está muito bom e pode ajudar muita gente, mas estava meio que perdido... O tópico fala da biblioteca BASS.DLL para manipulção de áudio digital e os exemplos estão em DELPHI, logo, resolvi por o texto aqui no fórum de Delphi, linguagem que eu adoro! Aqui vai...
8<--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
O BASS é incrível... Toca um monte de coisas e está preparado para tudo. A função [b:4b46a1b915]BASS_ChannelGetData[/b:4b46a1b915] é prova disso. Com ela é possível ´ver o audio´. Isso não é loucura!
Quando você vê um osciloscópio (linhas) ou um analizador de espectro (barras) em um programa ou mesmo os ´peak meters´ daquele aparelho de som mais antigo, nós na verdade estamos vendo o audio. Há uma grande diferença entre o audio digital e o analogico, vocês devem saber. Mas como pretendo dissertar sobre a função BASS_ChannelGetData nada melhor do que falar do audio digital e de alguns conceitos básicos. Todos os exemploes citam um MP3 comum, isto é, um que seja [b:4b46a1b915]Stereo 16 bits com amostras a 44100Hz...[/b:4b46a1b915] O que, nao entendeu nada? Calma!
Vamos analizar...
Em um som digital, não é possível ler o audio sequencialmente sempre. Tudo que você ouve, até mesmo os CDs que você põe no seu aparelho de som, usam a tecnica digital, q consiste em pegar [b:4b46a1b915]pedaços muito pequenos e muito rapidamente[/b:4b46a1b915], dando a impressão de ser um audio contínuo... Na descrição, mais acima 16 bit significa que a cada ´intervalo de tempo´ serão lidos 16 bits do audio, ou 2 bytes... O tal ´Intervalo de Tempo´ é definido pela frequencia de amostragem. Nossa frequencia de amostragem é de 44100Hz, ou 44100 ciclos por segundo logo de posse dessas informações dá pra saber quantos bytes por segundo nós estamos lendo, veja
Como nós estamos tratando de um canal Stereo, isso quer dizer que nós estamos lendo [b:4b46a1b915]176.400 Bytes (176KB)[/b:4b46a1b915] em cada segundo!
Ora, se num som digital o audio acontece lendo 176KB por segundo e você nem percebe, então se nós pudessemos pegar a cada segundo os valores das amplitudes de cada faixa de frequencia dentro dos 176KB obtidos seria possível desenhar um gráfico com eles! Bingo, nós podemos! É para isso que serve a função BASS_ChannelGetData. [b:4b46a1b915]Essa função retorna num Buffer as amplitudes do audio sendo tocado no momento, lendo 176KB a cada execução[/b:4b46a1b915]. Quando se quer criar um grafico simples, ou uma visualização tipo Winamp, devemos usar a fução BASS_ChannelGetData em um loop, que fica circulando enquanto a musica estiver tocando, dessa maneira quando quisermos plotar um grafico usaremos o buffer sempre preenchido com os valores mais atualizados possiveis...
BASS_ChannelGetData é capaz de preencher um buffer com dois tipos de dados: Dados PCM (Pulse Code Modulation) e dados FFT (Fast Fourier Transform). O primeiro é como se fossem dados sem formato que podem ser usados na criação de ondas em linhas mais conhecidas como osciloscópios. Tais dados não são capazes de nos fornecer informações sobre frequencias mas dão uma idéia das ondas sonoras obtidas com o audio sendo tocado. O segundo tipo de dados (FFT) é mais sofisticado pois é capaz de retornar amplitudes por faixa de frequencias servido portanto para desenhar graficos de barras verticais, mas conhecidos como analizadores de espectro, alias, ´analizadores de espectro´ pois ele analiza um espectro de frequencias! Cada barra representa a amplitude numa frequencia.
Falemos do PCM.
A função BASS_ChannelGetData, em seu ultimo parametro (lengh) recebe a quantidade de dados, o tamanho dos dados a serem lidos do audio. Suponha que tenhamos criado um buffer com 2048 posições logo TWaveData = array [0..2047] of DWord. Sim, quando estamos pedindo dados PCM, utilizando no terceiro parametro um valor que corresponde a quantidade de dados a serem lidos, e nesse caso a função BASS_ChannelGetData preenche um buffer com valores DWord. Em nosso exemplo nós estamos lendo um máximo de 2048 DWords, isso é mais que suficiente para um osciloscópio.
Colocada num loop, que circula enquanto a musica toca, a função BASS_ChannelGetData ira preencher a cada ciclo do loop uma variavel do tipo TWaveData (buffer) com 2048 valores DWord. Paralelo a esse loop ou imediatamente apos preencher o buffer, deve-se usar a variavel do tipo TWaveData dentro de um loop que circula variando de 0 (primeiro elemento do buffer) até a largura da visualização que deve ser menor ou igual a 2047. O metodo de desenhar vc escolhe...
Como os dados PCM são a imagem do som, ele sempre retorna Stereo se o som for stereo... então os dados dos canais direito e esquerdo vem codificados dentro de cada valor DWOrd unico... usando LoWord no valor DWord vc obtém o valor do canal ESQUERDO usando HiWord no valor DWord vc obtém o valor do canal direito!
Agora o FFT.
função BASS_ChannelGetData, em seu ultimo parametro (lengh) pode receber também Flags Especiais que devem ser usadas quando se quer obter valores FFT... Essas Flags (as mais importantes) são:
BASS_DATA_FFT512 retorna 256 valores de ponto flutuante
BASS_DATA_FFT1024 retorna 512 valores de ponto flutuante
BASS_DATA_FFT2048 retorna 1024 valores de ponto flutuante
BASS_DATA_FFT4096 retorna 2048 valores de ponto flutuante
Normalmente os dados FFT são combinados em um unico canal (mono) mesmo q o som seja stereo usando o flag especial BASS_DATA_FFT_INDIVIDUAL combinado com qqr um dos acima, irá fazer com que os valores retornados correspondam aos canais direito e esquerdo de forma intercambiada dentro do buffer, ou seja o primeiro é o esquerdo, o segundo é o direito o terceiro é o esquerdo... left,right,left,right... Usando esse flag dá pra obter os valores das amplitudes em cada frequencia para os canais direito e esquerdo.
Como se pode ver... Só se obtem valores FFT usando-se as flags FFT descritas acima... Retornando valores de ponto flutuante (Single) que variam de zero (0) a um (1). Suponha que tenhamos criado um buffer com 512 posições logo TFFTData = array [0..511] of Single. Em nosso exemplo nós estamos lendo um máximo de 512 Singles, que correspondem a 512 frequencias diferentes que serão exibidas em barras.
Colocada num loop, que circula enquanto a musica toca, a função BASS_ChannelGetData ira preencher a cada ciclo do loop uma variavel do tipo TFFTData (buffer) com 512 valores Single. Paralelo a esse loop ou imediatamente apos preencher o buffer, deve-se usar a variavel do tipo TFFTData dentro de um loop que circula variando de 1 (segundo elemento do buffer) até a largura da visualização que deve ser menor ou igual a 511. O metodo de desenhar vc escolhe...
Perceba que o loop q circula por entre os elementos do buffer nao começa em 0 (zero), mas sim 1 isso pq o primeiro elemento do buffer é conhecido como DC (Direct Current) que representa um som de 0Hz que nao existe na vida real. As amostras de audio (samples) não devem ter qualquer DC, mas provavelmente terão devido a imprecisões do equipamento de gravação que fora utilizado. Vc não ouve o DC, exceto um ´clck´ quando incia ou pára a reprodução.
Resumo:
Usando a função BASS_ChannelGetData vc consgue dados:
- PCM (osciloscopios)
- FFT (barras)
Para conseguir dados PCM simplesmente informe o tamanho de dados a serem lindo no terceiro parametro da função BASS_ChannelGetData. Os dados retornados sao do tipo DWord e representam o som exatemente como ele esta tocando. Os canais esquerdo e direito estao codificados dentro de cada valor dword: use LoWord para obter o valor esquerdo e HiWord para o direito.
Para conseguir dados FFT use as flags FFT de acordo com a quantidade de valores que você quer ler. Dados FFT são retornados de forma mono e são valores Single variando de 0 a 1, se quiser obter valores FFT separadamente use o Flag BASS_DATA_FFT_INDIVIDUAL. Nesse caso os valores são retornados assim: left, right, left...
No caso de querer usar FFT nunca use o primeiro valor. O primeiro valor do buffer é inutil. CADA valor FFT representa uma frequencia especifica assim use a formula abaixo para obter a frequencia de cada valor:
FFTBuffer e seus valores a partir do zero
0: DC (Ignore)
1: 1 x (44100/1024) = 43hz
2: 2 x (44100/1024) = 86hz
3: 3 x (44100/1024) = 129hz
44100 é a frequencia de amostragem
1024 significa que vc usou BASS_DATA_FFT1024 para preencher o buffer
Se forem outros valores para a frequencia de amostragem o flag, o calculo muda também
Recentemente voltei a usar este fórum e vi um tópico meu, que modéstia à parte está muito bom e pode ajudar muita gente, mas estava meio que perdido... O tópico fala da biblioteca BASS.DLL para manipulção de áudio digital e os exemplos estão em DELPHI, logo, resolvi por o texto aqui no fórum de Delphi, linguagem que eu adoro! Aqui vai...
8<--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
O BASS é incrível... Toca um monte de coisas e está preparado para tudo. A função [b:4b46a1b915]BASS_ChannelGetData[/b:4b46a1b915] é prova disso. Com ela é possível ´ver o audio´. Isso não é loucura!
Quando você vê um osciloscópio (linhas) ou um analizador de espectro (barras) em um programa ou mesmo os ´peak meters´ daquele aparelho de som mais antigo, nós na verdade estamos vendo o audio. Há uma grande diferença entre o audio digital e o analogico, vocês devem saber. Mas como pretendo dissertar sobre a função BASS_ChannelGetData nada melhor do que falar do audio digital e de alguns conceitos básicos. Todos os exemploes citam um MP3 comum, isto é, um que seja [b:4b46a1b915]Stereo 16 bits com amostras a 44100Hz...[/b:4b46a1b915] O que, nao entendeu nada? Calma!
Vamos analizar...
Stereo = 2 canais ou 2x 16 bit = tamanho da amostra 441000Hz = frequencia de amostragem
Em um som digital, não é possível ler o audio sequencialmente sempre. Tudo que você ouve, até mesmo os CDs que você põe no seu aparelho de som, usam a tecnica digital, q consiste em pegar [b:4b46a1b915]pedaços muito pequenos e muito rapidamente[/b:4b46a1b915], dando a impressão de ser um audio contínuo... Na descrição, mais acima 16 bit significa que a cada ´intervalo de tempo´ serão lidos 16 bits do audio, ou 2 bytes... O tal ´Intervalo de Tempo´ é definido pela frequencia de amostragem. Nossa frequencia de amostragem é de 44100Hz, ou 44100 ciclos por segundo logo de posse dessas informações dá pra saber quantos bytes por segundo nós estamos lendo, veja
2 bytes a cada ciclo numa frequencia de 44100 ciclos por segundo => 2 * 44100 = 88200
Como nós estamos tratando de um canal Stereo, isso quer dizer que nós estamos lendo [b:4b46a1b915]176.400 Bytes (176KB)[/b:4b46a1b915] em cada segundo!
Ora, se num som digital o audio acontece lendo 176KB por segundo e você nem percebe, então se nós pudessemos pegar a cada segundo os valores das amplitudes de cada faixa de frequencia dentro dos 176KB obtidos seria possível desenhar um gráfico com eles! Bingo, nós podemos! É para isso que serve a função BASS_ChannelGetData. [b:4b46a1b915]Essa função retorna num Buffer as amplitudes do audio sendo tocado no momento, lendo 176KB a cada execução[/b:4b46a1b915]. Quando se quer criar um grafico simples, ou uma visualização tipo Winamp, devemos usar a fução BASS_ChannelGetData em um loop, que fica circulando enquanto a musica estiver tocando, dessa maneira quando quisermos plotar um grafico usaremos o buffer sempre preenchido com os valores mais atualizados possiveis...
Resumindo: Chame BASS_ChannelGetData em um Loop a cada 15ms assim grantimos que o Buffer que será preenchido por ela conterá sempre os valores mais recentemente obtidos, com uma defasagem mínima (15ms)
BASS_ChannelGetData é capaz de preencher um buffer com dois tipos de dados: Dados PCM (Pulse Code Modulation) e dados FFT (Fast Fourier Transform). O primeiro é como se fossem dados sem formato que podem ser usados na criação de ondas em linhas mais conhecidas como osciloscópios. Tais dados não são capazes de nos fornecer informações sobre frequencias mas dão uma idéia das ondas sonoras obtidas com o audio sendo tocado. O segundo tipo de dados (FFT) é mais sofisticado pois é capaz de retornar amplitudes por faixa de frequencias servido portanto para desenhar graficos de barras verticais, mas conhecidos como analizadores de espectro, alias, ´analizadores de espectro´ pois ele analiza um espectro de frequencias! Cada barra representa a amplitude numa frequencia.
Falemos do PCM.
A função BASS_ChannelGetData, em seu ultimo parametro (lengh) recebe a quantidade de dados, o tamanho dos dados a serem lidos do audio. Suponha que tenhamos criado um buffer com 2048 posições logo TWaveData = array [0..2047] of DWord. Sim, quando estamos pedindo dados PCM, utilizando no terceiro parametro um valor que corresponde a quantidade de dados a serem lidos, e nesse caso a função BASS_ChannelGetData preenche um buffer com valores DWord. Em nosso exemplo nós estamos lendo um máximo de 2048 DWords, isso é mais que suficiente para um osciloscópio.
Colocada num loop, que circula enquanto a musica toca, a função BASS_ChannelGetData ira preencher a cada ciclo do loop uma variavel do tipo TWaveData (buffer) com 2048 valores DWord. Paralelo a esse loop ou imediatamente apos preencher o buffer, deve-se usar a variavel do tipo TWaveData dentro de um loop que circula variando de 0 (primeiro elemento do buffer) até a largura da visualização que deve ser menor ou igual a 2047. O metodo de desenhar vc escolhe...
Como os dados PCM são a imagem do som, ele sempre retorna Stereo se o som for stereo... então os dados dos canais direito e esquerdo vem codificados dentro de cada valor DWOrd unico... usando LoWord no valor DWord vc obtém o valor do canal ESQUERDO usando HiWord no valor DWord vc obtém o valor do canal direito!
Agora o FFT.
função BASS_ChannelGetData, em seu ultimo parametro (lengh) pode receber também Flags Especiais que devem ser usadas quando se quer obter valores FFT... Essas Flags (as mais importantes) são:
BASS_DATA_FFT512 retorna 256 valores de ponto flutuante
BASS_DATA_FFT1024 retorna 512 valores de ponto flutuante
BASS_DATA_FFT2048 retorna 1024 valores de ponto flutuante
BASS_DATA_FFT4096 retorna 2048 valores de ponto flutuante
Normalmente os dados FFT são combinados em um unico canal (mono) mesmo q o som seja stereo usando o flag especial BASS_DATA_FFT_INDIVIDUAL combinado com qqr um dos acima, irá fazer com que os valores retornados correspondam aos canais direito e esquerdo de forma intercambiada dentro do buffer, ou seja o primeiro é o esquerdo, o segundo é o direito o terceiro é o esquerdo... left,right,left,right... Usando esse flag dá pra obter os valores das amplitudes em cada frequencia para os canais direito e esquerdo.
Como se pode ver... Só se obtem valores FFT usando-se as flags FFT descritas acima... Retornando valores de ponto flutuante (Single) que variam de zero (0) a um (1). Suponha que tenhamos criado um buffer com 512 posições logo TFFTData = array [0..511] of Single. Em nosso exemplo nós estamos lendo um máximo de 512 Singles, que correspondem a 512 frequencias diferentes que serão exibidas em barras.
Colocada num loop, que circula enquanto a musica toca, a função BASS_ChannelGetData ira preencher a cada ciclo do loop uma variavel do tipo TFFTData (buffer) com 512 valores Single. Paralelo a esse loop ou imediatamente apos preencher o buffer, deve-se usar a variavel do tipo TFFTData dentro de um loop que circula variando de 1 (segundo elemento do buffer) até a largura da visualização que deve ser menor ou igual a 511. O metodo de desenhar vc escolhe...
Perceba que o loop q circula por entre os elementos do buffer nao começa em 0 (zero), mas sim 1 isso pq o primeiro elemento do buffer é conhecido como DC (Direct Current) que representa um som de 0Hz que nao existe na vida real. As amostras de audio (samples) não devem ter qualquer DC, mas provavelmente terão devido a imprecisões do equipamento de gravação que fora utilizado. Vc não ouve o DC, exceto um ´clck´ quando incia ou pára a reprodução.
Resumo:
Usando a função BASS_ChannelGetData vc consgue dados:
- PCM (osciloscopios)
- FFT (barras)
Para conseguir dados PCM simplesmente informe o tamanho de dados a serem lindo no terceiro parametro da função BASS_ChannelGetData. Os dados retornados sao do tipo DWord e representam o som exatemente como ele esta tocando. Os canais esquerdo e direito estao codificados dentro de cada valor dword: use LoWord para obter o valor esquerdo e HiWord para o direito.
Para conseguir dados FFT use as flags FFT de acordo com a quantidade de valores que você quer ler. Dados FFT são retornados de forma mono e são valores Single variando de 0 a 1, se quiser obter valores FFT separadamente use o Flag BASS_DATA_FFT_INDIVIDUAL. Nesse caso os valores são retornados assim: left, right, left...
No caso de querer usar FFT nunca use o primeiro valor. O primeiro valor do buffer é inutil. CADA valor FFT representa uma frequencia especifica assim use a formula abaixo para obter a frequencia de cada valor:
FFTBuffer e seus valores a partir do zero
0: DC (Ignore)
1: 1 x (44100/1024) = 43hz
2: 2 x (44100/1024) = 86hz
3: 3 x (44100/1024) = 129hz
44100 é a frequencia de amostragem
1024 significa que vc usou BASS_DATA_FFT1024 para preencher o buffer
Se forem outros valores para a frequencia de amostragem o flag, o calculo muda também
Carlos Filho
Curtir tópico
+ 0
Responder
Posts
08/01/2013
Bruno Signori
Muito interessante, fiz uns testes aqui, usei o seguinte codigo
No OnCreate:
e no Timer
BASS_ChannelGetData(Channel, @fft, BASS_DATA_FFT2048);
esse codigo me da o FFT do microfone...
gostaria de saber se tem como obter o FFT do audio que esta no output do meu pc.. tipo a musica do winamp, video do youtube, barulho do SO etc
gostaria de saber tambem, como obtenho o FFT de um arquivo de audio
e por ultimo, sera que tem como reproduzir um som com apenas os valores do FFT? por exemplo se existisse a funcao BASS_ChannelSetData(Channel, @fft, BASS_DATA_FFT2048);, aih voce fornecia os valores do FFT e o programa reproduz o audio com esse valores
obrigado
No OnCreate:
procedure TFrMedidorAudio.FormCreate(Sender: TObject);
var
I: Integer;
function DuffRecording(handle: HRECORD; const Buffer: Pointer; Length: DWORD; user: Pointer): Boolean; stdcall;
begin
Result := true; // continue recording
end;
begin
if not BASS_RecordInit(-1) then
begin
ShowMessage(Cant initialize device);
Halt;
end;
// start recording (44100hz mono 16-bit)
Channel := BASS_RecordStart(44100, 1, 0, @DuffRecording, NIL);
if Channel = 0 then
begin
ShowMessage(Cant start recording);
Halt;
end;
end;e no Timer
BASS_ChannelGetData(Channel, @fft, BASS_DATA_FFT2048);
esse codigo me da o FFT do microfone...
gostaria de saber se tem como obter o FFT do audio que esta no output do meu pc.. tipo a musica do winamp, video do youtube, barulho do SO etc
gostaria de saber tambem, como obtenho o FFT de um arquivo de audio
e por ultimo, sera que tem como reproduzir um som com apenas os valores do FFT? por exemplo se existisse a funcao BASS_ChannelSetData(Channel, @fft, BASS_DATA_FFT2048);, aih voce fornecia os valores do FFT e o programa reproduz o audio com esse valores
obrigado
Responder
Gostei + 0
08/01/2013
Carlos Filho
Olá!
Depois de tantos anos, nem me lembrava mais deste tópico! Infelizmente não posso te ajudar pois não estou mais por dentro deste assunto.
Ainda continuo achando a biblioteca BASS excelente! Aconselho você a procurar soluções em outros fóruns. Este da DevMedia parece estar caindo em desuso.
Dá uma olhada no forum do BASS em http://www.un4seen.com/
Obrigado por interessar-se!
Depois de tantos anos, nem me lembrava mais deste tópico! Infelizmente não posso te ajudar pois não estou mais por dentro deste assunto.
Ainda continuo achando a biblioteca BASS excelente! Aconselho você a procurar soluções em outros fóruns. Este da DevMedia parece estar caindo em desuso.
Dá uma olhada no forum do BASS em http://www.un4seen.com/
Obrigado por interessar-se!
Responder
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)