SlideShare une entreprise Scribd logo
1  sur  61
Télécharger pour lire hors ligne
AudioLazy
DSP (DSP (Digital Signal ProcessingDigital Signal Processing) expressivo e) expressivo e
em tempo real para o Pythonem tempo real para o Python
Projeto open source (GPLv3)Projeto open source (GPLv3)
http://pypi.python.org/pypi/audiolazyhttp://pypi.python.org/pypi/audiolazy
Copyright (C) 2012-2013Copyright (C) 2012-2013
Danilo de Jesus da Silva BelliniDanilo de Jesus da Silva Bellini
danilo [dot] bellini [at] gmail [dot] comdanilo [dot] bellini [at] gmail [dot] com
Parte 1
Aspectos geraisAspectos gerais
AudioLazy
● DSP (Digital Signal Processing) para áudio
– Análise
● MIR (Music Information Retrieval)
– Síntese
– Processamento
● Expressividade de código
– Facilita prototipação, simulação
● Tempo real (latência de 35ms é possível)
– Possibilita uso em aplicações finais
● 100% Python
– Multiplataforma
Justificativa
● Demanda e insatisfação com código existente
– Sustainable Software for Audio and Music Research
● ISMIR 2012 (Tutorial)
● DAFx 2012 (Tutorial)
– Software Carpentry
● Ausência de código fonte disponível
– Algoritmo de Klapuri (2008)
● Base para trabalhos futuros
Linguagem
Critério MatLab Octave PureData Python NumPy
Amostras Sim Sim Depende Sim Sim
Blocos Possível Possível Sim Possível Possível
Álgebra linear Sim Sim Depende Possível Sim
DSP Sim Sim Sim Possível Sim
Tempo real Não Não Sim Possível Não
Heterogeneidade Não Não Não Sim Possível
Avaliação tardia Não Não Depende Sim Não
Funções de ordem
superior
Não Não Não Sim Não
Orientação a objetos Possível Possível Não Sim Sim
Linguagem de uso
geral
Não Não Não Sim Sim
Documentação Sim Sim Sim Sim Sim
Licença Proprietária GNU GPL
BSD
Modificada
PSFL BSD
Preço US$99.00 Gratuito Gratuito Gratuito Gratuito
Código fonte (Fechado) C++ C C, Python
C, Fortran,
Python
Outras linguagens
● CAS (Computer
Algebra System)
– Wolfram Mathematica
– SymPy
● C, C++, Java
– Estáticas
– Imperativo
– S/ ênfase em ser
expressivo
● DSL (Domain Specific
Language)
– FAUST
– CSound
– SuperCollider
– ChunK
● Pacotes
– YAAFE
– MARLib
Resultados cobertura de código
(Testes automatizados)
--------------- coverage: platform linux2, python 2.7.3-final-0 ---------------
Name Stmts Miss Branch BrPart Cover Missing
------------------------------------------------------------
__init__ 44 1 18 4 92% 72
lazy_analysis 124 3 62 4 96% 210, 258-259
lazy_auditory 60 0 14 0 100%
lazy_core 130 7 56 5 94% 93-94, 108, 151, 211, [...]
lazy_filters 508 180 249 118 61% 53, 60, 81, 91, [...]
lazy_io 123 41 38 23 60% 35-37, 58-72, 76, 80, [...]
lazy_itertools 14 3 10 8 54% 61-64
lazy_lpc 127 15 42 7 87% 120, 134-135, [...]
lazy_math 59 1 28 0 99% 131
lazy_midi 54 5 26 3 90% 70, 111, 150, 156, 158
lazy_misc 208 28 138 30 83% 136, 201-202, 239, [...]
lazy_poly 126 30 89 34 70% 90, 146-149, 160, [...]
lazy_stream 144 2 56 4 97% 62, 606
lazy_synth 241 50 118 48 73% 277-299, 319-323, [...]
------------------------------------------------------------
TOTAL 1962 366 944 288 77%
========================= 5501 passed in 23.59 seconds =========================
--------------- coverage: platform linux2, python 2.7.3-final-0 ---------------
Name Stmts Miss Branch BrPart Cover Missing
------------------------------------------------------------
__init__ 44 1 18 4 92% 72
lazy_analysis 124 3 62 4 96% 210, 258-259
lazy_auditory 60 0 14 0 100%
lazy_core 130 7 56 5 94% 93-94, 108, 151, 211, [...]
lazy_filters 508 180 249 118 61% 53, 60, 81, 91, [...]
lazy_io 123 41 38 23 60% 35-37, 58-72, 76, 80, [...]
lazy_itertools 14 3 10 8 54% 61-64
lazy_lpc 127 15 42 7 87% 120, 134-135, [...]
lazy_math 59 1 28 0 99% 131
lazy_midi 54 5 26 3 90% 70, 111, 150, 156, 158
lazy_misc 208 28 138 30 83% 136, 201-202, 239, [...]
lazy_poly 126 30 89 34 70% 90, 146-149, 160, [...]
lazy_stream 144 2 56 4 97% 62, 606
lazy_synth 241 50 118 48 73% 277-299, 319-323, [...]
------------------------------------------------------------
TOTAL 1962 366 944 288 77%
========================= 5501 passed in 23.59 seconds =========================
Mock
Testes com oráculos
● 80 c/ o scipy.signal.lfilter
● 64 c/ o subpacote de otimização do SciPy
● 2 c/ o NumPy
import pytest
p = pytest.mark.parametrize
from scipy.signal import lfilter
from audiolazy import ZFilter, almost_eq
class TestZFilterScipy(object):
@p("a", [[1.], [3.], [1., 3.], [15., -17.2], [-18., 9.8, 0., 14.3]])
@p("b", [[1.], [-1.], [1., 0., -1.], [1., 3.]])
@p("data", [range(5), range(5, 0, -1), [7, 22, -5], [8., 3., 15.]])
def test_lfilter(self, a, b, data):
filt = ZFilter(b, a) # Cria um filtro com a AudioLazy
expected = lfilter(b, a, data).tolist() # Aplica o filtro com o SciPy
assert almost_eq(filt(data), expected) # Compara os resultados
import pytest
p = pytest.mark.parametrize
from scipy.signal import lfilter
from audiolazy import ZFilter, almost_eq
class TestZFilterScipy(object):
@p("a", [[1.], [3.], [1., 3.], [15., -17.2], [-18., 9.8, 0., 14.3]])
@p("b", [[1.], [-1.], [1., 0., -1.], [1., 3.]])
@p("data", [range(5), range(5, 0, -1), [7, 22, -5], [8., 3., 15.]])
def test_lfilter(self, a, b, data):
filt = ZFilter(b, a) # Cria um filtro com a AudioLazy
expected = lfilter(b, a, data).tolist() # Aplica o filtro com o SciPy
assert almost_eq(filt(data), expected) # Compara os resultados
Comparação de números em ponto
flutuante (IEEE 754)
● Valor absoluto (limiar “l”)
● Comparação pelo número de bits de mantissa (“t”
bits de tolerância para “s” bits de mantissa)
● Implementado na audiolazy.lazy_misc
– almost_eq_diff
– almost_eq
∣a−b∣≤l
∣a−b∣≤2(t − s−1)∣a+b∣
Parte 2
Síntese e processamento em tempo realSíntese e processamento em tempo real
“Hello world” em áudio
● Tocar uma senóide
– Console interativo
– Script
from audiolazy import *
rate = 44100
s, Hz = sHz(rate)
th = AudioIO().play(sinusoid(440 * Hz), rate=rate)
from audiolazy import *
rate = 44100
s, Hz = sHz(rate)
th = AudioIO().play(sinusoid(440 * Hz), rate=rate)
from audiolazy import *
rate = 44100
s, Hz = sHz(rate)
with AudioIO(True) as player:
player.play(sinusoid(440 * Hz), rate=rate)
from audiolazy import *
rate = 44100
s, Hz = sHz(rate)
with AudioIO(True) as player:
player.play(sinusoid(440 * Hz), rate=rate)
Multithread!
Síntese
● Aditiva
– Senóide (sinusoid)
– Table-lookup
● Senóide (sin_table)
● Dente de serra
(saw_table)
● AM
– Modulação em amplitude
– Modulação em anel
● FM
– Exemplo em wxPython
● Subtrativa
– Karplus-Strong
● Examplo com os corais
de J. S. Bach (Music21)
● Personalizada
– Construtor da classe
Stream
– Decorador tostream
Parte 3
StreamStream
Armazenamento: Estratégias para
avaliação de expressões
● Antecipada (eager)
– Chamada por valor (call by value)
– Avaliação ocorre antes da chamada
● Tardia (lazy)
– Chamada por nome (call by name)
● Reavaliação a cada chamada
– Chamada por necessidade (call by need)
● Memoize / Cache
● Há quem considere essa a única forma de avaliação
“preguiçosa” (lazy)
Avaliação tardia
● Evita cálculos desnecessários
● Estruturas de tamanho indefinido
– Potencialmente infinitas (e.g. contador)
● Fluxo de controle como abstração
In [1]: def gerador_123():
...: val = 1
...: while True:
...: yield val
...: val = val + 1 if val < 3 else 1
...:
In [2]: gerador_123
Out[2]: <function __main__.gerador_123>
In [3]: gerador_123()
Out[3]: <generator object gerador_123 at 0x...>
In [1]: def gerador_123():
...: val = 1
...: while True:
...: yield val
...: val = val + 1 if val < 3 else 1
...:
In [2]: gerador_123
Out[2]: <function __main__.gerador_123>
In [3]: gerador_123()
Out[3]: <generator object gerador_123 at 0x...>
In [4]: sinal = gerador_123()
In [5]: sinal.next()
Out[5]: 1
In [6]: sinal.next()
Out[6]: 2
In [7]: sinal.next()
Out[7]: 3
In [8]: sinal.next()
Out[8]: 1
In [4]: sinal = gerador_123()
In [5]: sinal.next()
Out[5]: 1
In [6]: sinal.next()
Out[6]: 2
In [7]: sinal.next()
Out[7]: 3
In [8]: sinal.next()
Out[8]: 1
Desempenho!
Para áudio, o que precisamos?
● Sequência de símbolos
– Símbolos são números, normalmente
● Tempo real
– Dados (elementos da sequência) inexistentes em
tempo de compilação
– Duração indefinida
– Não é necessário computar tudo para começar a
apresentar o resultado
Avaliação tardia!
Classe Stream
● Representa fluxo de informação (áudio)
● Iterável heterogêneo com operadores (baseado no
NumPy) e avaliação tardia
● Ausência de índices
– Limite de representação inteira (32 bits estouraria em
27:03:12)
In [1]: from audiolazy import Stream
In [2]: dados = Stream(5, 7, 1, 2, 5, 3, 2) # Periódico
In [3]: dados2 = Stream(0, 1) # Idem
In [4]: (dados + dados2).take(15)
Out[4]: [5, 8, 1, 3, 5, 4, 2, 6, 7, 2, 2, 6, 3, 3, 5]
In [1]: from audiolazy import Stream
In [2]: dados = Stream(5, 7, 1, 2, 5, 3, 2) # Periódico
In [3]: dados2 = Stream(0, 1) # Idem
In [4]: (dados + dados2).take(15)
Out[4]: [5, 8, 1, 3, 5, 4, 2, 6, 7, 2, 2, 6, 3, 3, 5]
Classe Stream
● Métodos, atributos e propriedades são aplicados
elemento a elemento
– Exceto “take”, “blocks” e outros da própria classe
Stream
● Finito ou de finalização indeterminada
In [5]: Stream([2, 3, 4]).take(5) # Lista de entrada
Out[5]: [2, 3, 4]
In [6]: Stream(2, 3, 4).take(5) # Números de entrada
Out[6]: [2, 3, 4, 2, 3]
In [7]: Stream(*[2, 3, 4]).take(5) # Lista com "*"
Out[7]: [2, 3, 4, 2, 3]
In [8]: (2 * Stream([1 + 2j, -3j, 7]).real).take(inf)
Out[8]: [2.0, 0.0, 14]
In [5]: Stream([2, 3, 4]).take(5) # Lista de entrada
Out[5]: [2, 3, 4]
In [6]: Stream(2, 3, 4).take(5) # Números de entrada
Out[6]: [2, 3, 4, 2, 3]
In [7]: Stream(*[2, 3, 4]).take(5) # Lista com "*"
Out[7]: [2, 3, 4, 2, 3]
In [8]: (2 * Stream([1 + 2j, -3j, 7]).real).take(inf)
Out[8]: [2.0, 0.0, 14]
Decorador tostream:
Geradores convertidos em Stream
● Função = Decorador(Função)
In [1]: from audiolazy import tostream
In [2]: @tostream
...: def impulse():
...: yield 1
...: while True:
...: yield 0
...:
In [3]: impulse # De fato, uma função
Out[3]: <function __main__.impulse>
In [4]: impulse() # Devolve um objeto Stream
Out[4]: <audiolazy.lazy_stream.Stream at 0x30824d0>
In [5]: impulse().take(5)
Out[5]: [1, 0, 0, 0, 0]
In [6]: (impulse() + 1).take(5) # Outro objeto instanciado
Out[6]: [2, 1, 1, 1, 1]
In [1]: from audiolazy import tostream
In [2]: @tostream
...: def impulse():
...: yield 1
...: while True:
...: yield 0
...:
In [3]: impulse # De fato, uma função
Out[3]: <function __main__.impulse>
In [4]: impulse() # Devolve um objeto Stream
Out[4]: <audiolazy.lazy_stream.Stream at 0x30824d0>
In [5]: impulse().take(5)
Out[5]: [1, 0, 0, 0, 0]
In [6]: (impulse() + 1).take(5) # Outro objeto instanciado
Out[6]: [2, 1, 1, 1, 1]
Processamento em bloco
● Stream.blocks(size, hop)
– Qualquer salto (hop) positivo
– Se mudar a saída, a mudança persistirá na próxima
saída quando hop < size
● Saídas são a mesma fila circular implementada como
collections.deque
In [1]: data = Stream([1, 2, 3])
In [2]: blks = data.blocks(size=2, hop=1)
In [3]: [list(blk) for blk in blks]
Out[3]: [[1, 2], [2, 3]]
In [1]: data = Stream([1, 2, 3])
In [2]: blks = data.blocks(size=2, hop=1)
In [3]: [list(blk) for blk in blks]
Out[3]: [[1, 2], [2, 3]]
SymPy
Parte 4
FiltrosFiltros
Filtros LTI
(Lineares e invariantes no tempo)
““Digital signal processing is mainlyDigital signal processing is mainly
based on linear time-invariantbased on linear time-invariant
systems.systems.””
(Dutilleux, Dempwolf, Holters e Zölzer(Dutilleux, Dempwolf, Holters e Zölzer
DAFx, segunda edição, capítulo 4, p. 103)DAFx, segunda edição, capítulo 4, p. 103)
Ressonador com valor exato
Gammatone
● Três modelos
– Slaney
– Klapuri
● 4 ressonadores em cascata
– Implementação genérica (qualquer ordem)
● Teoremas
Derivadas
● Prova por indução
Parte 5
MIRMIR
((Music Information RetrievalMusic Information Retrieval))
Altura, croma, timbre
● Som de Shepard
– Altura (pitch height)
– Croma (pitch chroma)
● Timbre
– Brilho
– Envoltória espectral
– Envoltória dinâmica
Série harmônica
● F0, 2F0, 3F0, 4F0 …
– 100 Hz, 200 Hz, 300 Hz... Comb!
freqs = [str2freq(note) for note in "E2 G#2 B2".split()] # Mi maior
filt = ParallelFilter(comb.tau(freq_to_lag(freq * Hz), .1 * s)
for freq in freqs)
filt.plot(samples=8192, rate=rate, min_freq=220*Hz, max_freq=880*Hz).show()
freqs = [str2freq(note) for note in "E2 G#2 B2".split()] # Mi maior
filt = ParallelFilter(comb.tau(freq_to_lag(freq * Hz), .1 * s)
for freq in freqs)
filt.plot(samples=8192, rate=rate, min_freq=220*Hz, max_freq=880*Hz).show()
Inteiros?
Racionais?
Primos?
2+ oitava
ZCR
Taxa de cruzamentos no zero
In [15]: pitch1.take(10) # Resultado em Hz
Out[15]:
[872.0947265625001,
882.861328125,
872.0947265625001,
882.861328125,
882.861328125,
882.861328125,
882.861328125,
872.0947265625001,
882.861328125,
872.0947265625001]
In [16]: freq2str(pitch1).take(10) # Resultado em nomes de notas
Out[16]:
['A5+5.62%',
'A5+5.62%',
'A5+5.62%',
'A5+5.62%',
'A5+5.62%',
'A5-15.62%',
'A5+5.62%',
'A5-15.62%',
'A5+5.62%',
'A5+5.62%']
In [15]: pitch1.take(10) # Resultado em Hz
Out[15]:
[872.0947265625001,
882.861328125,
872.0947265625001,
882.861328125,
882.861328125,
882.861328125,
882.861328125,
872.0947265625001,
882.861328125,
872.0947265625001]
In [16]: freq2str(pitch1).take(10) # Resultado em nomes de notas
Out[16]:
['A5+5.62%',
'A5+5.62%',
'A5+5.62%',
'A5+5.62%',
'A5+5.62%',
'A5-15.62%',
'A5+5.62%',
'A5-15.62%',
'A5+5.62%',
'A5+5.62%']
pitch1 = zcross_pitch(data1) / Hzpitch1 = zcross_pitch(data1) / Hz
@tostream
def zcross_pitch(sig, size=2048):
"Devolve a altura em cada bloco com o dado tamanho"
for blk in zcross(sig, hysteresis=.2).blocks(size):
yield lag_to_freq(2. * size / sum(blk))
@tostream
def zcross_pitch(sig, size=2048):
"Devolve a altura em cada bloco com o dado tamanho"
for blk in zcross(sig, hysteresis=.2).blocks(size):
yield lag_to_freq(2. * size / sum(blk))
data1 = .5 * sinusoid(880 * Hz)
data1 += .5 * saw_table(880*3 * Hz)
data1 *= .9 + .1 * white_noise()
data1 = .5 * sinusoid(880 * Hz)
data1 += .5 * saw_table(880*3 * Hz)
data1 *= .9 + .1 * white_noise()
AMDF (Average Magnitude Difference
Function)
Ainda sobre frequência fundamental e
periodicidade ...
● SDF (Square Difference Function)
● ACF (Autocorrelação)
– Inverso à AMDF e SDF (aqui queremos o maior valor)
● MPM (McLeod e Wyvill)
– Utilizar ACF para “normalizar” SDF
DFT ?!?
Autocorrelação
Transcrição por envoltória dinâmica
Transformada discreta de Hilbert
Algoritmo de Klapuri (2008)
Múltiplas frequências fundamentais
Algoritmo de Klapuri (2008)
Múltiplas frequências fundamentais
Algoritmo de Klapuri (2008)
Múltiplas frequências fundamentais
Algoritmo de Klapuri (2008)
Múltiplas frequências fundamentais
white_noise() * (1 + sinusoid(185 * Hz))white_noise() * (1 + sinusoid(185 * Hz))
Algoritmo de Klapuri (2008)
Múltiplas frequências fundamentais
● Envoltória espectral
● Adaptações
– Evitar repetição
– Polifonia máxima
● Sempre acerta pelo
menos uma nota
● Sem otimizações
Entrada “G2 D4 D5”
Saída [296.081543, 589.471436, 294.735718]
[ D4 + 14.19% , D5 + 6.3% , D4 + 6.3% ]
Entrada “C1 C2 C3 C4”
Saída [263.781738, 131.890869, 66.3940430, 44.1430664]
[ C4 + 14.21% , C3 + 14.21% , C2 + 25.95% , F1 + 19.31% ]
Entrada “F#4 G4 G#4”
Saída [44.1430664, 48.4497070, 371.4477538]
[ F1 + 19.31% , G1 − 19.53% , F#4 + 6.79% ]
from audiolazy import *
rate = 22050
s, Hz = sHz(rate)
size = 512
table = sin_table.harmonize({1: 1, 2: 5, 3: 3, 4: 2, 6: 9, 8: 1}).normalize()
data = table(str2freq("Bb3") * Hz).take(size) # Nota si bemol da 3a oitava
filt = lpc(data, order=14) # Filtro de análise
G = 1e-2 # Ganho apenas para alinhamento na visualização com a DFT
# Filtro de síntese
(G / filt).plot(blk=data, rate=rate, samples=1024, unwrap=False).show()
from audiolazy import *
rate = 22050
s, Hz = sHz(rate)
size = 512
table = sin_table.harmonize({1: 1, 2: 5, 3: 3, 4: 2, 6: 9, 8: 1}).normalize()
data = table(str2freq("Bb3") * Hz).take(size) # Nota si bemol da 3a oitava
filt = lpc(data, order=14) # Filtro de análise
G = 1e-2 # Ganho apenas para alinhamento na visualização com a DFT
# Filtro de síntese
(G / filt).plot(blk=data, rate=rate, samples=1024, unwrap=False).show()
Envoltória espectral
LPC - Predição Linear
Decomposição cromática
● Filtros gammatone
– Paralelo
● Oitavas
In [1]: from audiolazy import octaves
In [2]: octaves(440)
Out[2]: [27.5, 55.0, 110.0, 220.0, 440, 880, 1760, 3520, 7040, 14080]
In [1]: from audiolazy import octaves
In [2]: octaves(440)
Out[2]: [27.5, 55.0, 110.0, 220.0, 440, 880, 1760, 3520, 7040, 14080]
from __future__ import division
from audiolazy import *
def cromafb(classes=12, rate):
s, Hz = sHz(rate)
cg = gammatone_erb_constants(4)[0]
fb = 440
return [
ParallelFilter(
gammatone.sampled(f*Hz, cg*erb(f))
for f in octaves(fb * 2**(n/classes))
) for n in xrange(classes)
]
rate = 44100
bank = cromafb(rate=rate)
bank[0].plot(freq_scale="log", rate=rate)
from __future__ import division
from audiolazy import *
def cromafb(classes=12, rate):
s, Hz = sHz(rate)
cg = gammatone_erb_constants(4)[0]
fb = 440
return [
ParallelFilter(
gammatone.sampled(f*Hz, cg*erb(f))
for f in octaves(fb * 2**(n/classes))
) for n in xrange(classes)
]
rate = 44100
bank = cromafb(rate=rate)
bank[0].plot(freq_scale="log", rate=rate)
Cromagrama
Diferenciação
Parte 6
Aspectos de ImplementaçãoAspectos de Implementação
AbstractOperatorOverloaderMeta
● Metaclasse
– Classe cujas instâncias são classes
● Abstrata
– Classe com recursos especificados porém sem
implementação
● Sobrecarga massiva de operadores:
– Binários
– Binários reversos
– Unários
Objeto window
Um dicionário de estratégias
In [1]: from audiolazy import window
In [2]: window # Vejamos as estratégias disponíveis
Out[2]:
{('bartlett',): <function audiolazy.lazy_analysis.bartlett>,
('blackman',): <function audiolazy.lazy_analysis.blackman>,
('hamming',): <function audiolazy.lazy_analysis.hamming>,
('hann', 'hanning'): <function audiolazy.lazy_analysis.hann>,
('rectangular', 'rect'): <function audiolazy.lazy_analysis.rectangular>,
('triangular', 'triangle'): <function audiolazy.lazy_analysis.triangular>}
In [3]: window["rect"](3) # Obtém a estratégia, chamando com 1 argumento
Out[3]: [1.0, 1.0, 1.0]
In [4]: window.triangle(3) # Idem, mas feito com outra sintaxe (dicionário)
Out[4]: [0.5, 1.0, 0.5]
In [5]: hm_wnd = window.hamming # Referenciando fora do dicionário
In [6]: hm_wnd # Esta estratégia é uma função comum
Out[6]: <function audiolazy.lazy_analysis.hamming>
In [1]: from audiolazy import window
In [2]: window # Vejamos as estratégias disponíveis
Out[2]:
{('bartlett',): <function audiolazy.lazy_analysis.bartlett>,
('blackman',): <function audiolazy.lazy_analysis.blackman>,
('hamming',): <function audiolazy.lazy_analysis.hamming>,
('hann', 'hanning'): <function audiolazy.lazy_analysis.hann>,
('rectangular', 'rect'): <function audiolazy.lazy_analysis.rectangular>,
('triangular', 'triangle'): <function audiolazy.lazy_analysis.triangular>}
In [3]: window["rect"](3) # Obtém a estratégia, chamando com 1 argumento
Out[3]: [1.0, 1.0, 1.0]
In [4]: window.triangle(3) # Idem, mas feito com outra sintaxe (dicionário)
Out[4]: [0.5, 1.0, 0.5]
In [5]: hm_wnd = window.hamming # Referenciando fora do dicionário
In [6]: hm_wnd # Esta estratégia é uma função comum
Out[6]: <function audiolazy.lazy_analysis.hamming>
Polinômios
● Necessário para os filtros lineares
● Baseados em dicionário
– Memória
– Expoente negativo (Laurent)
– Expoente fracionário (soma de potências)
● Coeficientes podem ser objetos Stream, símbolos
do SymPy, etc.
Filtros
● Implementação direta I
– Evita multiplicação por 1
– Não cria os termos com coeficiente nulo
– Ainda ineficiente quando longo (e.g. FIR, comb)
● JIT (Just in Time)
– Cada filtro é criado e compilado em tempo de
execução
– Permite filtros variantes no tempo gerais e eficientes
Quantização em ponto flutuante
Módulos
Nome Descrição
lazy_analysis Análise de áudio
lazy_auditory Modelagem do aparato auditivo humano periférico
lazy_core Núcleo com as três classes de fundamentação do pacote
lazy_filters Filtros
lazy_io Gravação e reprodução de áudio (via PyAudio), multi-thread
lazy_itertools Conteúdo da itertools “decorado” ou adaptado para objetos Stream
lazy_lpc Codificação linear preditiva (LPC)
lazy_math Funções matemáticas para uso em iteráveis com manutenção de tipo
lazy_midi Representação MIDI e relações entre nota e frequência (altura)
lazy_misc Diversas ferramentas de uso geral e constantes
lazy_poly Polinômios
lazy_stream Definição da classe Stream e derivadas
lazy_synth Pequeno sintetizador
Classes
Nome Bases (herança) Módulo Descrição
AudioIO object lazy_io Reprodutor/gravador de áudio
AudioThread threading.Thread lazy_io Thread representando objetos sendo reproduzidos
LinearFilterProperties object lazy_filters Mixin com conversores de propriedades de filtros lineares
LinearFilter LinearFilterProperties lazy_filters Filtro linear
ZFilter LinearFilter lazy_filters Filtro linear representado por equações em Z
FilterList list, LinearFilterProperties lazy_filters Lista de filtros
CascadeFilter FilterList lazy_filters Filtros em cascata
ParallelFilter FilterList lazy_filters Filtros em paralelo
Poly object lazy_poly Polinômios, polinômios de Laurent, soma de potências
TableLookup object lazy_synth Sintetizador por consulta à tabela
MultiKeyDict dict lazy_core Dicionário multi-chave
StrategyDict MultiKeyDict lazy_core Dicionário de estratégias
StrategyDictInstance StrategyDict lazy_core Uma classe para cada dicionário de estratégias
Stream collections.Iterable lazy_stream Iterável com operadores elemento a elemento e avaliação tardia
ControlStream Stream lazy_stream Stream que devolve um valor controlável, permitindo
interatividade
Streamix Stream lazy_stream Misturador (mixer) de objetos Stream baseado na temporização
do MIDI
StreamTeeHub Stream lazy_stream Gerenciador de cópias de Stream
MemoryLeakWarning Warning lazy_stream Número de usos de um StreamTeeHub menor que o especificado
ParCorError ZeroDivisionError lazy_lpc Erro ao tentar obter coeficientes PARCOR
Diagrama de classes
(Relações internas)
● Classes “centrais”
– AbstractOperatorOverloaderMeta
– Stream
● StrategyDict possui instâncias
– Diagrama omite informações importantes
Dicionários de estratégias presentes
na AudioLazy
Nome Estratégias Módulo Descrição
window 6 lazy_analysis Funções de janelamento ou
apodização
envelope 3 lazy_analysis Filtros de obtenção de envoltória
dinâmica
maverage 3 lazy_analysis Criador de filtros de média móvel
erb 2 lazy_auditory Largura de banda equivalente
retangular (ERB)
gammatone 3 lazy_auditory Filtros gammatone
comb 3 lazy_filters Filtros comb
resonator 4 lazy_filters Ressonadores
lowpass 2 lazy_filters Passa-baixas
highpass 1 lazy_filters Passa-altas
lpc 5 lazy_lpc Codificação linear preditiva (LPC)
Documentação
● Docstrings: documentação no código
– Uso em ambientes interativos
– reStructuredText
– Organização em seções
● Spyder
● Sphinx
– Conversão automática do sistema de seções para o formato do
Sphinx
– Muitos formatos: LaTeX (PDF, DVI, PS), ePUB, HTML, TexInfo, etc.
● Apresentação, instruções de instalação e exemplos básicos
– Integração com MatPlotLib, Music21, wxPython, Tkinter, etc.
Exemplos de implementação de partes
da AudioLazy
def levinson_durbin(acdata, order):
def inner(a, b):
return sum(acdata[abs(i-j)] * ai * bj
for i, ai in enumerate(a.numlist)
for j, bj in enumerate(b.numlist)
)
A = ZFilter(1)
for m in range(1, order + 1):
B = A(1 / z) * z ** -m
A -= inner(A, z ** -m) / inner(B, B) * B
return A
def levinson_durbin(acdata, order):
def inner(a, b):
return sum(acdata[abs(i-j)] * ai * bj
for i, ai in enumerate(a.numlist)
for j, bj in enumerate(b.numlist)
)
A = ZFilter(1)
for m in range(1, order + 1):
B = A(1 / z) * z ** -m
A -= inner(A, z ** -m) / inner(B, B) * B
return A
Parte 7
FinalizaçãoFinalização
Situação atual (PyPI)
Versão
Downloads
(2013-02-15)
Downloads
(2013-05-01)
0.01 432 707
0.02 432 709
0.03 209 491
0.04 Não existia 328
Valores
mínimos
Conclusões
● Tempo real em Python
● Expressividade + avaliação tardia
– Modularidade
● Multiparadigma
– Funcional
– Reflexivo
– Objetos
● Filtros digitais a partir de filtros analógicos
● Orientação a testes
● Padrão IEEE 754
CPython PyPy
AudioLazy 271.49 ms 57.98 ms 53.24 ms
NumPy 19.45 ms 22.78 ms 21.06 ms
Benchmark: Síntese FM
Possíveis continuações para o
desenvolvimento da AudioLazy
● Análise
– FFT
– Heurísticas para transcrição
– Outras transformadas
● Modelagem audição
– Outros modelos (Lyon, Seneff,
gamma chirp, etc.)
– Conversão entre x-dB e ERB
● Síntese e processamento
– Wah, phaser, flanger, chorus, eco,
compressor, noise gate, limiter, …
● Testes
– 100%
– Mock MatPlotLib
● Filtros
– Atrasos/expoentes variantes no tempo
– Interpolação
– Frações parciais
– Otimização
– Escrita no tempo
– SymPy
– Treliça
● Outros
– Python 3.3
– Integrar com PureData
– I/O MIDI
– Plugins (e.g. Vamp)
– Tutorial
– Logo
Obrigado!
Perguntas?Perguntas?
Fork me on GitHubFork me on GitHub
https://github.com/danilobellini/audiolazyhttps://github.com/danilobellini/audiolazy

Contenu connexe

En vedette

Jennifer Dent
Jennifer DentJennifer Dent
Jennifer DentBioDundee
 
Sinclair, joseph ebay the smart way
Sinclair, joseph   ebay the smart waySinclair, joseph   ebay the smart way
Sinclair, joseph ebay the smart wayJacques Bouchard
 
Ed 114 fasciculo-cap-vii-equipamentos-para-subestacoes-de-t&amp;d
Ed 114 fasciculo-cap-vii-equipamentos-para-subestacoes-de-t&amp;dEd 114 fasciculo-cap-vii-equipamentos-para-subestacoes-de-t&amp;d
Ed 114 fasciculo-cap-vii-equipamentos-para-subestacoes-de-t&amp;dCarlos Roberto Gonçalves
 
Morning routines
Morning routinesMorning routines
Morning routinesMercedes S
 
Exchange program ppt
Exchange program pptExchange program ppt
Exchange program pptjmverson
 

En vedette (9)

Jennifer Dent
Jennifer DentJennifer Dent
Jennifer Dent
 
Sinclair, joseph ebay the smart way
Sinclair, joseph   ebay the smart waySinclair, joseph   ebay the smart way
Sinclair, joseph ebay the smart way
 
Ed 114 fasciculo-cap-vii-equipamentos-para-subestacoes-de-t&amp;d
Ed 114 fasciculo-cap-vii-equipamentos-para-subestacoes-de-t&amp;dEd 114 fasciculo-cap-vii-equipamentos-para-subestacoes-de-t&amp;d
Ed 114 fasciculo-cap-vii-equipamentos-para-subestacoes-de-t&amp;d
 
Isle marie yoga week
Isle marie yoga weekIsle marie yoga week
Isle marie yoga week
 
Presentation hydroxycut
Presentation hydroxycutPresentation hydroxycut
Presentation hydroxycut
 
Html
HtmlHtml
Html
 
Morning routines
Morning routinesMorning routines
Morning routines
 
Smb agency handbook
Smb agency handbookSmb agency handbook
Smb agency handbook
 
Exchange program ppt
Exchange program pptExchange program ppt
Exchange program ppt
 

Similaire à Audio DSP em Python com AudioLazy

Simpósio Unicruz: OpenCV + Python (parte 1)
Simpósio Unicruz: OpenCV + Python (parte 1)Simpósio Unicruz: OpenCV + Python (parte 1)
Simpósio Unicruz: OpenCV + Python (parte 1)Cristiano Rafael Steffens
 
Zabbix monitorando o zimbra collaboration 8.8 (1)
Zabbix   monitorando o zimbra collaboration 8.8 (1)Zabbix   monitorando o zimbra collaboration 8.8 (1)
Zabbix monitorando o zimbra collaboration 8.8 (1)PAULO R. DEOLINDO JUNIOR
 
Principais conceitos e técnicas em vetorização
Principais conceitos e técnicas em vetorizaçãoPrincipais conceitos e técnicas em vetorização
Principais conceitos e técnicas em vetorizaçãoIntel Software Brasil
 
Mini Curso de Python para Coding Dojo
Mini Curso de Python para Coding DojoMini Curso de Python para Coding Dojo
Mini Curso de Python para Coding DojoFabricio NErdmann
 
Iteraveis e geradores em Python
Iteraveis e geradores em PythonIteraveis e geradores em Python
Iteraveis e geradores em PythonLuciano Ramalho
 
Introdução a linguagem Python
Introdução a linguagem PythonIntrodução a linguagem Python
Introdução a linguagem PythonLuciano Ramalho
 
V2 - Microcontroladores: a revolucao do arduino
V2 - Microcontroladores: a revolucao do arduinoV2 - Microcontroladores: a revolucao do arduino
V2 - Microcontroladores: a revolucao do arduinoSamir Siqueira
 
Python para quem sabe Python (aula 2)
Python para quem sabe Python (aula 2)Python para quem sabe Python (aula 2)
Python para quem sabe Python (aula 2)Luciano Ramalho
 
Introdução ao SystemTap - João Avelino Bellomo Filho - Tchelinux Caxias 2018
Introdução ao SystemTap - João Avelino Bellomo Filho - Tchelinux Caxias 2018Introdução ao SystemTap - João Avelino Bellomo Filho - Tchelinux Caxias 2018
Introdução ao SystemTap - João Avelino Bellomo Filho - Tchelinux Caxias 2018Tchelinux
 
Introdução à Linguagem de programação Python
Introdução à Linguagem de programação PythonIntrodução à Linguagem de programação Python
Introdução à Linguagem de programação Pythondmmartins
 
(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3
(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3
(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3Danilo J. S. Bellini
 
Iniciando em Python
Iniciando em PythonIniciando em Python
Iniciando em PythonRober Guerra
 
fuchigami-2019-minicurso-julia-ermac-bauru.pdf
fuchigami-2019-minicurso-julia-ermac-bauru.pdffuchigami-2019-minicurso-julia-ermac-bauru.pdf
fuchigami-2019-minicurso-julia-ermac-bauru.pdfLEANDROHENRICKSILVAN
 
O que mudou no Ruby 1.9
O que mudou no Ruby 1.9O que mudou no Ruby 1.9
O que mudou no Ruby 1.9Nando Vieira
 
sys._current_frames(), Radiografando seu software em tempo real
 sys._current_frames(), Radiografando seu software em tempo real sys._current_frames(), Radiografando seu software em tempo real
sys._current_frames(), Radiografando seu software em tempo realLeonardo Rochael Almeida
 

Similaire à Audio DSP em Python com AudioLazy (20)

Simpósio Unicruz: OpenCV + Python (parte 1)
Simpósio Unicruz: OpenCV + Python (parte 1)Simpósio Unicruz: OpenCV + Python (parte 1)
Simpósio Unicruz: OpenCV + Python (parte 1)
 
Zabbix monitorando o zimbra collaboration 8.8 (1)
Zabbix   monitorando o zimbra collaboration 8.8 (1)Zabbix   monitorando o zimbra collaboration 8.8 (1)
Zabbix monitorando o zimbra collaboration 8.8 (1)
 
Iteraveis e geradores
Iteraveis e geradoresIteraveis e geradores
Iteraveis e geradores
 
Principais conceitos e técnicas em vetorização
Principais conceitos e técnicas em vetorizaçãoPrincipais conceitos e técnicas em vetorização
Principais conceitos e técnicas em vetorização
 
Mini Curso de Python para Coding Dojo
Mini Curso de Python para Coding DojoMini Curso de Python para Coding Dojo
Mini Curso de Python para Coding Dojo
 
Iteraveis e geradores em Python
Iteraveis e geradores em PythonIteraveis e geradores em Python
Iteraveis e geradores em Python
 
Introdução a linguagem Python
Introdução a linguagem PythonIntrodução a linguagem Python
Introdução a linguagem Python
 
V2 - Microcontroladores: a revolucao do arduino
V2 - Microcontroladores: a revolucao do arduinoV2 - Microcontroladores: a revolucao do arduino
V2 - Microcontroladores: a revolucao do arduino
 
Inpe
InpeInpe
Inpe
 
Python
PythonPython
Python
 
Python para quem sabe Python (aula 2)
Python para quem sabe Python (aula 2)Python para quem sabe Python (aula 2)
Python para quem sabe Python (aula 2)
 
Introdução ao SystemTap - João Avelino Bellomo Filho - Tchelinux Caxias 2018
Introdução ao SystemTap - João Avelino Bellomo Filho - Tchelinux Caxias 2018Introdução ao SystemTap - João Avelino Bellomo Filho - Tchelinux Caxias 2018
Introdução ao SystemTap - João Avelino Bellomo Filho - Tchelinux Caxias 2018
 
Introdução à Linguagem de programação Python
Introdução à Linguagem de programação PythonIntrodução à Linguagem de programação Python
Introdução à Linguagem de programação Python
 
Guia Matlab
Guia MatlabGuia Matlab
Guia Matlab
 
PostgreSQL 8.4
PostgreSQL 8.4PostgreSQL 8.4
PostgreSQL 8.4
 
(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3
(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3
(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3
 
Iniciando em Python
Iniciando em PythonIniciando em Python
Iniciando em Python
 
fuchigami-2019-minicurso-julia-ermac-bauru.pdf
fuchigami-2019-minicurso-julia-ermac-bauru.pdffuchigami-2019-minicurso-julia-ermac-bauru.pdf
fuchigami-2019-minicurso-julia-ermac-bauru.pdf
 
O que mudou no Ruby 1.9
O que mudou no Ruby 1.9O que mudou no Ruby 1.9
O que mudou no Ruby 1.9
 
sys._current_frames(), Radiografando seu software em tempo real
 sys._current_frames(), Radiografando seu software em tempo real sys._current_frames(), Radiografando seu software em tempo real
sys._current_frames(), Radiografando seu software em tempo real
 

Plus de Danilo J. S. Bellini

(2018-10-18) [ETEC Uirapuru] Segurança da Informação
(2018-10-18) [ETEC Uirapuru] Segurança da Informação(2018-10-18) [ETEC Uirapuru] Segurança da Informação
(2018-10-18) [ETEC Uirapuru] Segurança da InformaçãoDanilo J. S. Bellini
 
(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono
(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono
(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask AssíncronoDanilo J. S. Bellini
 
(2018-07-14) [Just Python] Números no Python!
(2018-07-14) [Just Python] Números no Python!(2018-07-14) [Just Python] Números no Python!
(2018-07-14) [Just Python] Números no Python!Danilo J. S. Bellini
 
(2017-08-12) [GruPy-SP] AudioLazy no GruPy! (+LV2)
(2017-08-12) [GruPy-SP] AudioLazy no GruPy! (+LV2)(2017-08-12) [GruPy-SP] AudioLazy no GruPy! (+LV2)
(2017-08-12) [GruPy-SP] AudioLazy no GruPy! (+LV2)Danilo J. S. Bellini
 
(2017-07-22) [TDC] Audiolazy em 2017!
(2017-07-22) [TDC] Audiolazy em 2017!(2017-07-22) [TDC] Audiolazy em 2017!
(2017-07-22) [TDC] Audiolazy em 2017!Danilo J. S. Bellini
 
(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)
(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)
(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)Danilo J. S. Bellini
 
(2016-08-13) [Grupy-SP] Plugin pytest-doctest-custom v1.0.0
(2016-08-13) [Grupy-SP] Plugin pytest-doctest-custom v1.0.0(2016-08-13) [Grupy-SP] Plugin pytest-doctest-custom v1.0.0
(2016-08-13) [Grupy-SP] Plugin pytest-doctest-custom v1.0.0Danilo J. S. Bellini
 
(2015-03-14) [Grupy-SP] Projetos Open Source, como colaborar?
(2015-03-14) [Grupy-SP] Projetos Open Source, como colaborar?(2015-03-14) [Grupy-SP] Projetos Open Source, como colaborar?
(2015-03-14) [Grupy-SP] Projetos Open Source, como colaborar?Danilo J. S. Bellini
 
(2015-01-29/30) [WTA2015] Adaptatividade em Python (Tutorial)
(2015-01-29/30) [WTA2015] Adaptatividade em Python (Tutorial)(2015-01-29/30) [WTA2015] Adaptatividade em Python (Tutorial)
(2015-01-29/30) [WTA2015] Adaptatividade em Python (Tutorial)Danilo J. S. Bellini
 
(2014-11-05) [PythonBrasil] Testando com py.test e tox
(2014-11-05) [PythonBrasil] Testando com py.test e tox(2014-11-05) [PythonBrasil] Testando com py.test e tox
(2014-11-05) [PythonBrasil] Testando com py.test e toxDanilo J. S. Bellini
 
(2014-10-27) [SETI-UFLA-MG] AudioLazy
(2014-10-27) [SETI-UFLA-MG] AudioLazy(2014-10-27) [SETI-UFLA-MG] AudioLazy
(2014-10-27) [SETI-UFLA-MG] AudioLazyDanilo J. S. Bellini
 
(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!
(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!
(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!Danilo J. S. Bellini
 
(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...
(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...
(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...Danilo J. S. Bellini
 
(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)
(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)
(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)Danilo J. S. Bellini
 
(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy
(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy
(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazyDanilo J. S. Bellini
 
(2013-10-17) [LatinoWare] Automatizando o GIMP com Python
(2013-10-17) [LatinoWare] Automatizando o GIMP com Python(2013-10-17) [LatinoWare] Automatizando o GIMP com Python
(2013-10-17) [LatinoWare] Automatizando o GIMP com PythonDanilo J. S. Bellini
 
(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3
(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3
(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3Danilo J. S. Bellini
 

Plus de Danilo J. S. Bellini (20)

(2018-10-18) [ETEC Uirapuru] Segurança da Informação
(2018-10-18) [ETEC Uirapuru] Segurança da Informação(2018-10-18) [ETEC Uirapuru] Segurança da Informação
(2018-10-18) [ETEC Uirapuru] Segurança da Informação
 
(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono
(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono
(2018-08-25) [Flask Conf] Introdução ao Sanic - O Flask Assíncrono
 
(2018-07-14) [Just Python] Números no Python!
(2018-07-14) [Just Python] Números no Python!(2018-07-14) [Just Python] Números no Python!
(2018-07-14) [Just Python] Números no Python!
 
(2017-08-12) [GruPy-SP] AudioLazy no GruPy! (+LV2)
(2017-08-12) [GruPy-SP] AudioLazy no GruPy! (+LV2)(2017-08-12) [GruPy-SP] AudioLazy no GruPy! (+LV2)
(2017-08-12) [GruPy-SP] AudioLazy no GruPy! (+LV2)
 
(2017-07-22) [TDC] Audiolazy em 2017!
(2017-07-22) [TDC] Audiolazy em 2017!(2017-07-22) [TDC] Audiolazy em 2017!
(2017-07-22) [TDC] Audiolazy em 2017!
 
(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)
(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)
(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)
 
(2016-08-13) [Grupy-SP] Plugin pytest-doctest-custom v1.0.0
(2016-08-13) [Grupy-SP] Plugin pytest-doctest-custom v1.0.0(2016-08-13) [Grupy-SP] Plugin pytest-doctest-custom v1.0.0
(2016-08-13) [Grupy-SP] Plugin pytest-doctest-custom v1.0.0
 
(2015-03-14) [Grupy-SP] Projetos Open Source, como colaborar?
(2015-03-14) [Grupy-SP] Projetos Open Source, como colaborar?(2015-03-14) [Grupy-SP] Projetos Open Source, como colaborar?
(2015-03-14) [Grupy-SP] Projetos Open Source, como colaborar?
 
(2015-01-29/30) [WTA2015] Adaptatividade em Python (Tutorial)
(2015-01-29/30) [WTA2015] Adaptatividade em Python (Tutorial)(2015-01-29/30) [WTA2015] Adaptatividade em Python (Tutorial)
(2015-01-29/30) [WTA2015] Adaptatividade em Python (Tutorial)
 
(2014-11-05) [PythonBrasil] Testando com py.test e tox
(2014-11-05) [PythonBrasil] Testando com py.test e tox(2014-11-05) [PythonBrasil] Testando com py.test e tox
(2014-11-05) [PythonBrasil] Testando com py.test e tox
 
(2014-10-27) [SETI-UFLA-MG] AudioLazy
(2014-10-27) [SETI-UFLA-MG] AudioLazy(2014-10-27) [SETI-UFLA-MG] AudioLazy
(2014-10-27) [SETI-UFLA-MG] AudioLazy
 
(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!
(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!
(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!
 
(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...
(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...
(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...
 
(2014-04-16) [Garoa HC] Strategy
(2014-04-16) [Garoa HC] Strategy(2014-04-16) [Garoa HC] Strategy
(2014-04-16) [Garoa HC] Strategy
 
(2013-12-18) [Garoa HC] AudioLazy
(2013-12-18) [Garoa HC] AudioLazy(2013-12-18) [Garoa HC] AudioLazy
(2013-12-18) [Garoa HC] AudioLazy
 
(2014-03-26) [7masters] AudioLazy
(2014-03-26) [7masters] AudioLazy(2014-03-26) [7masters] AudioLazy
(2014-03-26) [7masters] AudioLazy
 
(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)
(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)
(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)
 
(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy
(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy
(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy
 
(2013-10-17) [LatinoWare] Automatizando o GIMP com Python
(2013-10-17) [LatinoWare] Automatizando o GIMP com Python(2013-10-17) [LatinoWare] Automatizando o GIMP com Python
(2013-10-17) [LatinoWare] Automatizando o GIMP com Python
 
(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3
(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3
(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3
 

Audio DSP em Python com AudioLazy

  • 1. AudioLazy DSP (DSP (Digital Signal ProcessingDigital Signal Processing) expressivo e) expressivo e em tempo real para o Pythonem tempo real para o Python Projeto open source (GPLv3)Projeto open source (GPLv3) http://pypi.python.org/pypi/audiolazyhttp://pypi.python.org/pypi/audiolazy Copyright (C) 2012-2013Copyright (C) 2012-2013 Danilo de Jesus da Silva BelliniDanilo de Jesus da Silva Bellini danilo [dot] bellini [at] gmail [dot] comdanilo [dot] bellini [at] gmail [dot] com
  • 3. AudioLazy ● DSP (Digital Signal Processing) para áudio – Análise ● MIR (Music Information Retrieval) – Síntese – Processamento ● Expressividade de código – Facilita prototipação, simulação ● Tempo real (latência de 35ms é possível) – Possibilita uso em aplicações finais ● 100% Python – Multiplataforma
  • 4. Justificativa ● Demanda e insatisfação com código existente – Sustainable Software for Audio and Music Research ● ISMIR 2012 (Tutorial) ● DAFx 2012 (Tutorial) – Software Carpentry ● Ausência de código fonte disponível – Algoritmo de Klapuri (2008) ● Base para trabalhos futuros
  • 5. Linguagem Critério MatLab Octave PureData Python NumPy Amostras Sim Sim Depende Sim Sim Blocos Possível Possível Sim Possível Possível Álgebra linear Sim Sim Depende Possível Sim DSP Sim Sim Sim Possível Sim Tempo real Não Não Sim Possível Não Heterogeneidade Não Não Não Sim Possível Avaliação tardia Não Não Depende Sim Não Funções de ordem superior Não Não Não Sim Não Orientação a objetos Possível Possível Não Sim Sim Linguagem de uso geral Não Não Não Sim Sim Documentação Sim Sim Sim Sim Sim Licença Proprietária GNU GPL BSD Modificada PSFL BSD Preço US$99.00 Gratuito Gratuito Gratuito Gratuito Código fonte (Fechado) C++ C C, Python C, Fortran, Python
  • 6. Outras linguagens ● CAS (Computer Algebra System) – Wolfram Mathematica – SymPy ● C, C++, Java – Estáticas – Imperativo – S/ ênfase em ser expressivo ● DSL (Domain Specific Language) – FAUST – CSound – SuperCollider – ChunK ● Pacotes – YAAFE – MARLib
  • 7. Resultados cobertura de código (Testes automatizados) --------------- coverage: platform linux2, python 2.7.3-final-0 --------------- Name Stmts Miss Branch BrPart Cover Missing ------------------------------------------------------------ __init__ 44 1 18 4 92% 72 lazy_analysis 124 3 62 4 96% 210, 258-259 lazy_auditory 60 0 14 0 100% lazy_core 130 7 56 5 94% 93-94, 108, 151, 211, [...] lazy_filters 508 180 249 118 61% 53, 60, 81, 91, [...] lazy_io 123 41 38 23 60% 35-37, 58-72, 76, 80, [...] lazy_itertools 14 3 10 8 54% 61-64 lazy_lpc 127 15 42 7 87% 120, 134-135, [...] lazy_math 59 1 28 0 99% 131 lazy_midi 54 5 26 3 90% 70, 111, 150, 156, 158 lazy_misc 208 28 138 30 83% 136, 201-202, 239, [...] lazy_poly 126 30 89 34 70% 90, 146-149, 160, [...] lazy_stream 144 2 56 4 97% 62, 606 lazy_synth 241 50 118 48 73% 277-299, 319-323, [...] ------------------------------------------------------------ TOTAL 1962 366 944 288 77% ========================= 5501 passed in 23.59 seconds ========================= --------------- coverage: platform linux2, python 2.7.3-final-0 --------------- Name Stmts Miss Branch BrPart Cover Missing ------------------------------------------------------------ __init__ 44 1 18 4 92% 72 lazy_analysis 124 3 62 4 96% 210, 258-259 lazy_auditory 60 0 14 0 100% lazy_core 130 7 56 5 94% 93-94, 108, 151, 211, [...] lazy_filters 508 180 249 118 61% 53, 60, 81, 91, [...] lazy_io 123 41 38 23 60% 35-37, 58-72, 76, 80, [...] lazy_itertools 14 3 10 8 54% 61-64 lazy_lpc 127 15 42 7 87% 120, 134-135, [...] lazy_math 59 1 28 0 99% 131 lazy_midi 54 5 26 3 90% 70, 111, 150, 156, 158 lazy_misc 208 28 138 30 83% 136, 201-202, 239, [...] lazy_poly 126 30 89 34 70% 90, 146-149, 160, [...] lazy_stream 144 2 56 4 97% 62, 606 lazy_synth 241 50 118 48 73% 277-299, 319-323, [...] ------------------------------------------------------------ TOTAL 1962 366 944 288 77% ========================= 5501 passed in 23.59 seconds ========================= Mock
  • 8. Testes com oráculos ● 80 c/ o scipy.signal.lfilter ● 64 c/ o subpacote de otimização do SciPy ● 2 c/ o NumPy import pytest p = pytest.mark.parametrize from scipy.signal import lfilter from audiolazy import ZFilter, almost_eq class TestZFilterScipy(object): @p("a", [[1.], [3.], [1., 3.], [15., -17.2], [-18., 9.8, 0., 14.3]]) @p("b", [[1.], [-1.], [1., 0., -1.], [1., 3.]]) @p("data", [range(5), range(5, 0, -1), [7, 22, -5], [8., 3., 15.]]) def test_lfilter(self, a, b, data): filt = ZFilter(b, a) # Cria um filtro com a AudioLazy expected = lfilter(b, a, data).tolist() # Aplica o filtro com o SciPy assert almost_eq(filt(data), expected) # Compara os resultados import pytest p = pytest.mark.parametrize from scipy.signal import lfilter from audiolazy import ZFilter, almost_eq class TestZFilterScipy(object): @p("a", [[1.], [3.], [1., 3.], [15., -17.2], [-18., 9.8, 0., 14.3]]) @p("b", [[1.], [-1.], [1., 0., -1.], [1., 3.]]) @p("data", [range(5), range(5, 0, -1), [7, 22, -5], [8., 3., 15.]]) def test_lfilter(self, a, b, data): filt = ZFilter(b, a) # Cria um filtro com a AudioLazy expected = lfilter(b, a, data).tolist() # Aplica o filtro com o SciPy assert almost_eq(filt(data), expected) # Compara os resultados
  • 9. Comparação de números em ponto flutuante (IEEE 754) ● Valor absoluto (limiar “l”) ● Comparação pelo número de bits de mantissa (“t” bits de tolerância para “s” bits de mantissa) ● Implementado na audiolazy.lazy_misc – almost_eq_diff – almost_eq ∣a−b∣≤l ∣a−b∣≤2(t − s−1)∣a+b∣
  • 10. Parte 2 Síntese e processamento em tempo realSíntese e processamento em tempo real
  • 11. “Hello world” em áudio ● Tocar uma senóide – Console interativo – Script from audiolazy import * rate = 44100 s, Hz = sHz(rate) th = AudioIO().play(sinusoid(440 * Hz), rate=rate) from audiolazy import * rate = 44100 s, Hz = sHz(rate) th = AudioIO().play(sinusoid(440 * Hz), rate=rate) from audiolazy import * rate = 44100 s, Hz = sHz(rate) with AudioIO(True) as player: player.play(sinusoid(440 * Hz), rate=rate) from audiolazy import * rate = 44100 s, Hz = sHz(rate) with AudioIO(True) as player: player.play(sinusoid(440 * Hz), rate=rate) Multithread!
  • 12. Síntese ● Aditiva – Senóide (sinusoid) – Table-lookup ● Senóide (sin_table) ● Dente de serra (saw_table) ● AM – Modulação em amplitude – Modulação em anel ● FM – Exemplo em wxPython ● Subtrativa – Karplus-Strong ● Examplo com os corais de J. S. Bach (Music21) ● Personalizada – Construtor da classe Stream – Decorador tostream
  • 14. Armazenamento: Estratégias para avaliação de expressões ● Antecipada (eager) – Chamada por valor (call by value) – Avaliação ocorre antes da chamada ● Tardia (lazy) – Chamada por nome (call by name) ● Reavaliação a cada chamada – Chamada por necessidade (call by need) ● Memoize / Cache ● Há quem considere essa a única forma de avaliação “preguiçosa” (lazy)
  • 15. Avaliação tardia ● Evita cálculos desnecessários ● Estruturas de tamanho indefinido – Potencialmente infinitas (e.g. contador) ● Fluxo de controle como abstração In [1]: def gerador_123(): ...: val = 1 ...: while True: ...: yield val ...: val = val + 1 if val < 3 else 1 ...: In [2]: gerador_123 Out[2]: <function __main__.gerador_123> In [3]: gerador_123() Out[3]: <generator object gerador_123 at 0x...> In [1]: def gerador_123(): ...: val = 1 ...: while True: ...: yield val ...: val = val + 1 if val < 3 else 1 ...: In [2]: gerador_123 Out[2]: <function __main__.gerador_123> In [3]: gerador_123() Out[3]: <generator object gerador_123 at 0x...> In [4]: sinal = gerador_123() In [5]: sinal.next() Out[5]: 1 In [6]: sinal.next() Out[6]: 2 In [7]: sinal.next() Out[7]: 3 In [8]: sinal.next() Out[8]: 1 In [4]: sinal = gerador_123() In [5]: sinal.next() Out[5]: 1 In [6]: sinal.next() Out[6]: 2 In [7]: sinal.next() Out[7]: 3 In [8]: sinal.next() Out[8]: 1 Desempenho!
  • 16. Para áudio, o que precisamos? ● Sequência de símbolos – Símbolos são números, normalmente ● Tempo real – Dados (elementos da sequência) inexistentes em tempo de compilação – Duração indefinida – Não é necessário computar tudo para começar a apresentar o resultado Avaliação tardia!
  • 17. Classe Stream ● Representa fluxo de informação (áudio) ● Iterável heterogêneo com operadores (baseado no NumPy) e avaliação tardia ● Ausência de índices – Limite de representação inteira (32 bits estouraria em 27:03:12) In [1]: from audiolazy import Stream In [2]: dados = Stream(5, 7, 1, 2, 5, 3, 2) # Periódico In [3]: dados2 = Stream(0, 1) # Idem In [4]: (dados + dados2).take(15) Out[4]: [5, 8, 1, 3, 5, 4, 2, 6, 7, 2, 2, 6, 3, 3, 5] In [1]: from audiolazy import Stream In [2]: dados = Stream(5, 7, 1, 2, 5, 3, 2) # Periódico In [3]: dados2 = Stream(0, 1) # Idem In [4]: (dados + dados2).take(15) Out[4]: [5, 8, 1, 3, 5, 4, 2, 6, 7, 2, 2, 6, 3, 3, 5]
  • 18. Classe Stream ● Métodos, atributos e propriedades são aplicados elemento a elemento – Exceto “take”, “blocks” e outros da própria classe Stream ● Finito ou de finalização indeterminada In [5]: Stream([2, 3, 4]).take(5) # Lista de entrada Out[5]: [2, 3, 4] In [6]: Stream(2, 3, 4).take(5) # Números de entrada Out[6]: [2, 3, 4, 2, 3] In [7]: Stream(*[2, 3, 4]).take(5) # Lista com "*" Out[7]: [2, 3, 4, 2, 3] In [8]: (2 * Stream([1 + 2j, -3j, 7]).real).take(inf) Out[8]: [2.0, 0.0, 14] In [5]: Stream([2, 3, 4]).take(5) # Lista de entrada Out[5]: [2, 3, 4] In [6]: Stream(2, 3, 4).take(5) # Números de entrada Out[6]: [2, 3, 4, 2, 3] In [7]: Stream(*[2, 3, 4]).take(5) # Lista com "*" Out[7]: [2, 3, 4, 2, 3] In [8]: (2 * Stream([1 + 2j, -3j, 7]).real).take(inf) Out[8]: [2.0, 0.0, 14]
  • 19. Decorador tostream: Geradores convertidos em Stream ● Função = Decorador(Função) In [1]: from audiolazy import tostream In [2]: @tostream ...: def impulse(): ...: yield 1 ...: while True: ...: yield 0 ...: In [3]: impulse # De fato, uma função Out[3]: <function __main__.impulse> In [4]: impulse() # Devolve um objeto Stream Out[4]: <audiolazy.lazy_stream.Stream at 0x30824d0> In [5]: impulse().take(5) Out[5]: [1, 0, 0, 0, 0] In [6]: (impulse() + 1).take(5) # Outro objeto instanciado Out[6]: [2, 1, 1, 1, 1] In [1]: from audiolazy import tostream In [2]: @tostream ...: def impulse(): ...: yield 1 ...: while True: ...: yield 0 ...: In [3]: impulse # De fato, uma função Out[3]: <function __main__.impulse> In [4]: impulse() # Devolve um objeto Stream Out[4]: <audiolazy.lazy_stream.Stream at 0x30824d0> In [5]: impulse().take(5) Out[5]: [1, 0, 0, 0, 0] In [6]: (impulse() + 1).take(5) # Outro objeto instanciado Out[6]: [2, 1, 1, 1, 1]
  • 20. Processamento em bloco ● Stream.blocks(size, hop) – Qualquer salto (hop) positivo – Se mudar a saída, a mudança persistirá na próxima saída quando hop < size ● Saídas são a mesma fila circular implementada como collections.deque In [1]: data = Stream([1, 2, 3]) In [2]: blks = data.blocks(size=2, hop=1) In [3]: [list(blk) for blk in blks] Out[3]: [[1, 2], [2, 3]] In [1]: data = Stream([1, 2, 3]) In [2]: blks = data.blocks(size=2, hop=1) In [3]: [list(blk) for blk in blks] Out[3]: [[1, 2], [2, 3]]
  • 21. SymPy
  • 23. Filtros LTI (Lineares e invariantes no tempo) ““Digital signal processing is mainlyDigital signal processing is mainly based on linear time-invariantbased on linear time-invariant systems.systems.”” (Dutilleux, Dempwolf, Holters e Zölzer(Dutilleux, Dempwolf, Holters e Zölzer DAFx, segunda edição, capítulo 4, p. 103)DAFx, segunda edição, capítulo 4, p. 103)
  • 25. Gammatone ● Três modelos – Slaney – Klapuri ● 4 ressonadores em cascata – Implementação genérica (qualquer ordem) ● Teoremas
  • 27. Parte 5 MIRMIR ((Music Information RetrievalMusic Information Retrieval))
  • 28. Altura, croma, timbre ● Som de Shepard – Altura (pitch height) – Croma (pitch chroma) ● Timbre – Brilho – Envoltória espectral – Envoltória dinâmica
  • 29. Série harmônica ● F0, 2F0, 3F0, 4F0 … – 100 Hz, 200 Hz, 300 Hz... Comb! freqs = [str2freq(note) for note in "E2 G#2 B2".split()] # Mi maior filt = ParallelFilter(comb.tau(freq_to_lag(freq * Hz), .1 * s) for freq in freqs) filt.plot(samples=8192, rate=rate, min_freq=220*Hz, max_freq=880*Hz).show() freqs = [str2freq(note) for note in "E2 G#2 B2".split()] # Mi maior filt = ParallelFilter(comb.tau(freq_to_lag(freq * Hz), .1 * s) for freq in freqs) filt.plot(samples=8192, rate=rate, min_freq=220*Hz, max_freq=880*Hz).show() Inteiros? Racionais? Primos? 2+ oitava
  • 30. ZCR Taxa de cruzamentos no zero In [15]: pitch1.take(10) # Resultado em Hz Out[15]: [872.0947265625001, 882.861328125, 872.0947265625001, 882.861328125, 882.861328125, 882.861328125, 882.861328125, 872.0947265625001, 882.861328125, 872.0947265625001] In [16]: freq2str(pitch1).take(10) # Resultado em nomes de notas Out[16]: ['A5+5.62%', 'A5+5.62%', 'A5+5.62%', 'A5+5.62%', 'A5+5.62%', 'A5-15.62%', 'A5+5.62%', 'A5-15.62%', 'A5+5.62%', 'A5+5.62%'] In [15]: pitch1.take(10) # Resultado em Hz Out[15]: [872.0947265625001, 882.861328125, 872.0947265625001, 882.861328125, 882.861328125, 882.861328125, 882.861328125, 872.0947265625001, 882.861328125, 872.0947265625001] In [16]: freq2str(pitch1).take(10) # Resultado em nomes de notas Out[16]: ['A5+5.62%', 'A5+5.62%', 'A5+5.62%', 'A5+5.62%', 'A5+5.62%', 'A5-15.62%', 'A5+5.62%', 'A5-15.62%', 'A5+5.62%', 'A5+5.62%'] pitch1 = zcross_pitch(data1) / Hzpitch1 = zcross_pitch(data1) / Hz @tostream def zcross_pitch(sig, size=2048): "Devolve a altura em cada bloco com o dado tamanho" for blk in zcross(sig, hysteresis=.2).blocks(size): yield lag_to_freq(2. * size / sum(blk)) @tostream def zcross_pitch(sig, size=2048): "Devolve a altura em cada bloco com o dado tamanho" for blk in zcross(sig, hysteresis=.2).blocks(size): yield lag_to_freq(2. * size / sum(blk)) data1 = .5 * sinusoid(880 * Hz) data1 += .5 * saw_table(880*3 * Hz) data1 *= .9 + .1 * white_noise() data1 = .5 * sinusoid(880 * Hz) data1 += .5 * saw_table(880*3 * Hz) data1 *= .9 + .1 * white_noise()
  • 31. AMDF (Average Magnitude Difference Function)
  • 32. Ainda sobre frequência fundamental e periodicidade ... ● SDF (Square Difference Function) ● ACF (Autocorrelação) – Inverso à AMDF e SDF (aqui queremos o maior valor) ● MPM (McLeod e Wyvill) – Utilizar ACF para “normalizar” SDF DFT ?!?
  • 35. Algoritmo de Klapuri (2008) Múltiplas frequências fundamentais
  • 36. Algoritmo de Klapuri (2008) Múltiplas frequências fundamentais
  • 37. Algoritmo de Klapuri (2008) Múltiplas frequências fundamentais
  • 38. Algoritmo de Klapuri (2008) Múltiplas frequências fundamentais white_noise() * (1 + sinusoid(185 * Hz))white_noise() * (1 + sinusoid(185 * Hz))
  • 39. Algoritmo de Klapuri (2008) Múltiplas frequências fundamentais ● Envoltória espectral ● Adaptações – Evitar repetição – Polifonia máxima ● Sempre acerta pelo menos uma nota ● Sem otimizações Entrada “G2 D4 D5” Saída [296.081543, 589.471436, 294.735718] [ D4 + 14.19% , D5 + 6.3% , D4 + 6.3% ] Entrada “C1 C2 C3 C4” Saída [263.781738, 131.890869, 66.3940430, 44.1430664] [ C4 + 14.21% , C3 + 14.21% , C2 + 25.95% , F1 + 19.31% ] Entrada “F#4 G4 G#4” Saída [44.1430664, 48.4497070, 371.4477538] [ F1 + 19.31% , G1 − 19.53% , F#4 + 6.79% ]
  • 40. from audiolazy import * rate = 22050 s, Hz = sHz(rate) size = 512 table = sin_table.harmonize({1: 1, 2: 5, 3: 3, 4: 2, 6: 9, 8: 1}).normalize() data = table(str2freq("Bb3") * Hz).take(size) # Nota si bemol da 3a oitava filt = lpc(data, order=14) # Filtro de análise G = 1e-2 # Ganho apenas para alinhamento na visualização com a DFT # Filtro de síntese (G / filt).plot(blk=data, rate=rate, samples=1024, unwrap=False).show() from audiolazy import * rate = 22050 s, Hz = sHz(rate) size = 512 table = sin_table.harmonize({1: 1, 2: 5, 3: 3, 4: 2, 6: 9, 8: 1}).normalize() data = table(str2freq("Bb3") * Hz).take(size) # Nota si bemol da 3a oitava filt = lpc(data, order=14) # Filtro de análise G = 1e-2 # Ganho apenas para alinhamento na visualização com a DFT # Filtro de síntese (G / filt).plot(blk=data, rate=rate, samples=1024, unwrap=False).show() Envoltória espectral LPC - Predição Linear
  • 41. Decomposição cromática ● Filtros gammatone – Paralelo ● Oitavas In [1]: from audiolazy import octaves In [2]: octaves(440) Out[2]: [27.5, 55.0, 110.0, 220.0, 440, 880, 1760, 3520, 7040, 14080] In [1]: from audiolazy import octaves In [2]: octaves(440) Out[2]: [27.5, 55.0, 110.0, 220.0, 440, 880, 1760, 3520, 7040, 14080] from __future__ import division from audiolazy import * def cromafb(classes=12, rate): s, Hz = sHz(rate) cg = gammatone_erb_constants(4)[0] fb = 440 return [ ParallelFilter( gammatone.sampled(f*Hz, cg*erb(f)) for f in octaves(fb * 2**(n/classes)) ) for n in xrange(classes) ] rate = 44100 bank = cromafb(rate=rate) bank[0].plot(freq_scale="log", rate=rate) from __future__ import division from audiolazy import * def cromafb(classes=12, rate): s, Hz = sHz(rate) cg = gammatone_erb_constants(4)[0] fb = 440 return [ ParallelFilter( gammatone.sampled(f*Hz, cg*erb(f)) for f in octaves(fb * 2**(n/classes)) ) for n in xrange(classes) ] rate = 44100 bank = cromafb(rate=rate) bank[0].plot(freq_scale="log", rate=rate)
  • 44. Parte 6 Aspectos de ImplementaçãoAspectos de Implementação
  • 45. AbstractOperatorOverloaderMeta ● Metaclasse – Classe cujas instâncias são classes ● Abstrata – Classe com recursos especificados porém sem implementação ● Sobrecarga massiva de operadores: – Binários – Binários reversos – Unários
  • 46. Objeto window Um dicionário de estratégias In [1]: from audiolazy import window In [2]: window # Vejamos as estratégias disponíveis Out[2]: {('bartlett',): <function audiolazy.lazy_analysis.bartlett>, ('blackman',): <function audiolazy.lazy_analysis.blackman>, ('hamming',): <function audiolazy.lazy_analysis.hamming>, ('hann', 'hanning'): <function audiolazy.lazy_analysis.hann>, ('rectangular', 'rect'): <function audiolazy.lazy_analysis.rectangular>, ('triangular', 'triangle'): <function audiolazy.lazy_analysis.triangular>} In [3]: window["rect"](3) # Obtém a estratégia, chamando com 1 argumento Out[3]: [1.0, 1.0, 1.0] In [4]: window.triangle(3) # Idem, mas feito com outra sintaxe (dicionário) Out[4]: [0.5, 1.0, 0.5] In [5]: hm_wnd = window.hamming # Referenciando fora do dicionário In [6]: hm_wnd # Esta estratégia é uma função comum Out[6]: <function audiolazy.lazy_analysis.hamming> In [1]: from audiolazy import window In [2]: window # Vejamos as estratégias disponíveis Out[2]: {('bartlett',): <function audiolazy.lazy_analysis.bartlett>, ('blackman',): <function audiolazy.lazy_analysis.blackman>, ('hamming',): <function audiolazy.lazy_analysis.hamming>, ('hann', 'hanning'): <function audiolazy.lazy_analysis.hann>, ('rectangular', 'rect'): <function audiolazy.lazy_analysis.rectangular>, ('triangular', 'triangle'): <function audiolazy.lazy_analysis.triangular>} In [3]: window["rect"](3) # Obtém a estratégia, chamando com 1 argumento Out[3]: [1.0, 1.0, 1.0] In [4]: window.triangle(3) # Idem, mas feito com outra sintaxe (dicionário) Out[4]: [0.5, 1.0, 0.5] In [5]: hm_wnd = window.hamming # Referenciando fora do dicionário In [6]: hm_wnd # Esta estratégia é uma função comum Out[6]: <function audiolazy.lazy_analysis.hamming>
  • 47. Polinômios ● Necessário para os filtros lineares ● Baseados em dicionário – Memória – Expoente negativo (Laurent) – Expoente fracionário (soma de potências) ● Coeficientes podem ser objetos Stream, símbolos do SymPy, etc.
  • 48. Filtros ● Implementação direta I – Evita multiplicação por 1 – Não cria os termos com coeficiente nulo – Ainda ineficiente quando longo (e.g. FIR, comb) ● JIT (Just in Time) – Cada filtro é criado e compilado em tempo de execução – Permite filtros variantes no tempo gerais e eficientes
  • 50. Módulos Nome Descrição lazy_analysis Análise de áudio lazy_auditory Modelagem do aparato auditivo humano periférico lazy_core Núcleo com as três classes de fundamentação do pacote lazy_filters Filtros lazy_io Gravação e reprodução de áudio (via PyAudio), multi-thread lazy_itertools Conteúdo da itertools “decorado” ou adaptado para objetos Stream lazy_lpc Codificação linear preditiva (LPC) lazy_math Funções matemáticas para uso em iteráveis com manutenção de tipo lazy_midi Representação MIDI e relações entre nota e frequência (altura) lazy_misc Diversas ferramentas de uso geral e constantes lazy_poly Polinômios lazy_stream Definição da classe Stream e derivadas lazy_synth Pequeno sintetizador
  • 51. Classes Nome Bases (herança) Módulo Descrição AudioIO object lazy_io Reprodutor/gravador de áudio AudioThread threading.Thread lazy_io Thread representando objetos sendo reproduzidos LinearFilterProperties object lazy_filters Mixin com conversores de propriedades de filtros lineares LinearFilter LinearFilterProperties lazy_filters Filtro linear ZFilter LinearFilter lazy_filters Filtro linear representado por equações em Z FilterList list, LinearFilterProperties lazy_filters Lista de filtros CascadeFilter FilterList lazy_filters Filtros em cascata ParallelFilter FilterList lazy_filters Filtros em paralelo Poly object lazy_poly Polinômios, polinômios de Laurent, soma de potências TableLookup object lazy_synth Sintetizador por consulta à tabela MultiKeyDict dict lazy_core Dicionário multi-chave StrategyDict MultiKeyDict lazy_core Dicionário de estratégias StrategyDictInstance StrategyDict lazy_core Uma classe para cada dicionário de estratégias Stream collections.Iterable lazy_stream Iterável com operadores elemento a elemento e avaliação tardia ControlStream Stream lazy_stream Stream que devolve um valor controlável, permitindo interatividade Streamix Stream lazy_stream Misturador (mixer) de objetos Stream baseado na temporização do MIDI StreamTeeHub Stream lazy_stream Gerenciador de cópias de Stream MemoryLeakWarning Warning lazy_stream Número de usos de um StreamTeeHub menor que o especificado ParCorError ZeroDivisionError lazy_lpc Erro ao tentar obter coeficientes PARCOR
  • 52. Diagrama de classes (Relações internas) ● Classes “centrais” – AbstractOperatorOverloaderMeta – Stream ● StrategyDict possui instâncias – Diagrama omite informações importantes
  • 53. Dicionários de estratégias presentes na AudioLazy Nome Estratégias Módulo Descrição window 6 lazy_analysis Funções de janelamento ou apodização envelope 3 lazy_analysis Filtros de obtenção de envoltória dinâmica maverage 3 lazy_analysis Criador de filtros de média móvel erb 2 lazy_auditory Largura de banda equivalente retangular (ERB) gammatone 3 lazy_auditory Filtros gammatone comb 3 lazy_filters Filtros comb resonator 4 lazy_filters Ressonadores lowpass 2 lazy_filters Passa-baixas highpass 1 lazy_filters Passa-altas lpc 5 lazy_lpc Codificação linear preditiva (LPC)
  • 54. Documentação ● Docstrings: documentação no código – Uso em ambientes interativos – reStructuredText – Organização em seções ● Spyder ● Sphinx – Conversão automática do sistema de seções para o formato do Sphinx – Muitos formatos: LaTeX (PDF, DVI, PS), ePUB, HTML, TexInfo, etc. ● Apresentação, instruções de instalação e exemplos básicos – Integração com MatPlotLib, Music21, wxPython, Tkinter, etc.
  • 55. Exemplos de implementação de partes da AudioLazy def levinson_durbin(acdata, order): def inner(a, b): return sum(acdata[abs(i-j)] * ai * bj for i, ai in enumerate(a.numlist) for j, bj in enumerate(b.numlist) ) A = ZFilter(1) for m in range(1, order + 1): B = A(1 / z) * z ** -m A -= inner(A, z ** -m) / inner(B, B) * B return A def levinson_durbin(acdata, order): def inner(a, b): return sum(acdata[abs(i-j)] * ai * bj for i, ai in enumerate(a.numlist) for j, bj in enumerate(b.numlist) ) A = ZFilter(1) for m in range(1, order + 1): B = A(1 / z) * z ** -m A -= inner(A, z ** -m) / inner(B, B) * B return A
  • 57. Situação atual (PyPI) Versão Downloads (2013-02-15) Downloads (2013-05-01) 0.01 432 707 0.02 432 709 0.03 209 491 0.04 Não existia 328 Valores mínimos
  • 58. Conclusões ● Tempo real em Python ● Expressividade + avaliação tardia – Modularidade ● Multiparadigma – Funcional – Reflexivo – Objetos ● Filtros digitais a partir de filtros analógicos ● Orientação a testes ● Padrão IEEE 754
  • 59. CPython PyPy AudioLazy 271.49 ms 57.98 ms 53.24 ms NumPy 19.45 ms 22.78 ms 21.06 ms Benchmark: Síntese FM
  • 60. Possíveis continuações para o desenvolvimento da AudioLazy ● Análise – FFT – Heurísticas para transcrição – Outras transformadas ● Modelagem audição – Outros modelos (Lyon, Seneff, gamma chirp, etc.) – Conversão entre x-dB e ERB ● Síntese e processamento – Wah, phaser, flanger, chorus, eco, compressor, noise gate, limiter, … ● Testes – 100% – Mock MatPlotLib ● Filtros – Atrasos/expoentes variantes no tempo – Interpolação – Frações parciais – Otimização – Escrita no tempo – SymPy – Treliça ● Outros – Python 3.3 – Integrar com PureData – I/O MIDI – Plugins (e.g. Vamp) – Tutorial – Logo
  • 61. Obrigado! Perguntas?Perguntas? Fork me on GitHubFork me on GitHub https://github.com/danilobellini/audiolazyhttps://github.com/danilobellini/audiolazy