Your SlideShare is downloading. ×
  • Like
(2013-05-20) [DevInSampa] AudioLazy - DSP expressivo e em tempo real para o Python
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Now you can save presentations on your phone or tablet

Available for both IPhone and Android

Text the download link to your phone

Standard text messaging rates apply

(2013-05-20) [DevInSampa] AudioLazy - DSP expressivo e em tempo real para o Python

  • 481 views
Published

Slides da apresentação no DevInSampa 2013 (18 de maio), com algumas complementações e correções. Esses mesmos slides foram utilizados na apresentação feita no fisl 2014 (2013-07-05).

Slides da apresentação no DevInSampa 2013 (18 de maio), com algumas complementações e correções. Esses mesmos slides foram utilizados na apresentação feita no fisl 2014 (2013-07-05).

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
481
On SlideShare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
7
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. AudioLazy - DSP expressivo e emtempo real para o Pythonhttp://pypi.python.org/pypi/audiolazyhttp://pypi.python.org/pypi/audiolazyCopyright (C) 2012-2013Copyright (C) 2012-2013Danilo de Jesus da Silva Bellini <danilo.bellini@gmail.com>Danilo de Jesus da Silva Bellini <danilo.bellini@gmail.com>
  • 2. Parte 1Síntese! Show me the code!Go go go!Go go go!Não, Python!Não, Python!
  • 3. “Hello world” em áudio● Tocar uma senóide– Console interativo– Scriptfrom audiolazy import *rate = 44100s, Hz = sHz(rate)th = AudioIO().play(sinusoid(440 * Hz), rate=rate)from audiolazy import *rate = 44100s, Hz = sHz(rate)th = AudioIO().play(sinusoid(440 * Hz), rate=rate)from audiolazy import *rate = 44100s, Hz = sHz(rate)with AudioIO(True) as player:player.play(sinusoid(440 * Hz), rate=rate)from audiolazy import *rate = 44100s, Hz = sHz(rate)with AudioIO(True) as player:player.play(sinusoid(440 * Hz), rate=rate)Multithread!
  • 4. Síntese● ControlStream– Property “value”– Permite interatividade● Tempo real● Síntese– Ring Modulation - Senóide * Senóide– AM - Senóide * (1 + Senóide)– FM - Senóide(Senóide)– Subtrativa (e.g. Karplus-Strong)– Aditiva (e.g. TableLookup) Imagem daWikipediaExemplos!!!wxPython,Music21
  • 5. Parte 2Queremos mais itertools!!!repeat chain count imap ifilter izip ...repeat chain count imap ifilter izip ...Stream !Stream !
  • 6. Container para áudio● Tempo real– Amostras (dados/elementos) inexistentes...● ...em tempo de compilação (dados a serem coletados)● ...em tempo de execução (dados criados no futuro)– Duração possivelmente indefinida– Não deve ser necessário computar tudo para começara apresentar o resultado● Resultados parciais● Para cada amostra de entrada, deve haver uma de saída– Minimizar lag (atraso) entre entrada e saídaAvaliação tardia!
  • 7. Classe Stream● Iterável● Heterogêneo● Operadores– Elementwise/broadcastcomo no NumPy● Avaliação tardia– Lembra geradores● Já estávamos usando!– sinusoid,karplus_strong,ControlStream, ...● Ausência de índices– Limite de representaçãointeira (32 bitsestouraria em 27:03:12)In [1]: from audiolazy import StreamIn [2]: dados = Stream(5, 7, 1, 2, 5, 3, 2) # PeriódicoIn [3]: dados2 = Stream(0, 1) # IdemIn [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 StreamIn [2]: dados = Stream(5, 7, 1, 2, 5, 3, 2) # PeriódicoIn [3]: dados2 = Stream(0, 1) # IdemIn [4]: (dados + dados2).take(15)Out[4]: [5, 8, 1, 3, 5, 4, 2, 6, 7, 2, 2, 6, 3, 3, 5]
  • 8. Classe Stream● Métodos, atributos e propriedades são aplicadoselemento a elemento– Exceto quando existe na classe Stream (“take”,“blocks”, “peek”, “skip”, “limit”, ...)● Finito ou de finalização indeterminadaIn [5]: Stream([2, 3, 4]).take(5) # Lista de entradaOut[5]: [2, 3, 4]In [6]: Stream(2, 3, 4).take(5) # Números de entradaOut[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 entradaOut[5]: [2, 3, 4]In [6]: Stream(2, 3, 4).take(5) # Números de entradaOut[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]
  • 9. Decorador tostream:Geradores convertidos em Stream● Já foi aplicado a TODOS os itertools (e.g. count)!!!In [1]: from audiolazy import tostreamIn [2]: @tostream...: def impulse():...: yield 1...: while True:...: yield 0...:In [3]: impulse # De fato, uma funçãoOut[3]: <function __main__.impulse>In [4]: impulse() # Devolve um objeto StreamOut[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 instanciadoOut[6]: [2, 1, 1, 1, 1]In [1]: from audiolazy import tostreamIn [2]: @tostream...: def impulse():...: yield 1...: while True:...: yield 0...:In [3]: impulse # De fato, uma funçãoOut[3]: <function __main__.impulse>In [4]: impulse() # Devolve um objeto StreamOut[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 instanciadoOut[6]: [2, 1, 1, 1, 1]Síntesepersonalizada!(Acesso diretoàs amostras)
  • 10. Processamento em bloco● Stream.blocks(size, hop)– Qualquer salto (hop) positivo– Se mudar a saída, a mudança persistirá na próximasaída quando hop < size● Saídas são a mesma fila circular implementada comocollections.dequeIn [1]: data = Stream([1, 2, 3, 4, 5])In [2]: blks = data.blocks(size=2, hop=1)In [3]: [list(blk) for blk in blks]Out[3]: [[1, 2], [2, 3], [3, 4], [4, 5]]In [1]: data = Stream([1, 2, 3, 4, 5])In [2]: blks = data.blocks(size=2, hop=1)In [3]: [list(blk) for blk in blks]Out[3]: [[1, 2], [2, 3], [3, 4], [4, 5]]
  • 11. Parte 3FiltrosFiltros
  • 12. Filtros LTI(Lineares e invariantes no tempo)““Digital signal processing is mainlyDigital signal processing is mainlybased on linear time-invariantbased on linear time-invariantsystems.systems.””(Dutilleux, Dempwolf, Holters e Zölzer(Dutilleux, Dempwolf, Holters e ZölzerDAFx, segunda edição, capítulo 4, p. 103)DAFx, segunda edição, capítulo 4, p. 103)
  • 13. Transformada Z● Definição:● Interpretação:–Atrasoem kamostras!● Muitos “infinitos”– Teoremas● Possibilitam o uso prático(eliminam os “infinitos”)
  • 14. Exemplo de transformada Z● Acumulador ● Média móvelTá legal...mas, na prática, cadê o tal código?!Saída / Entrada, ouH(z) = Y(z) / X(z)
  • 15. Objeto “z”In [1]: from audiolazy import z, Stream, maverageIn [2]: M = 5In [3]: media_movel_5 = (1 - z ** -M) / (M * (1 - z ** -1))In [4]: acumulador = 1 / (1 - z ** -1)In [5]: media_movel_5(Stream(5)).take(10)Out[5]: [1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]In [6]: acumulador(Stream(5)).take(10)Out[6]: [5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0]In [7]: maverage.recursive(4)Out[7]:0.25 - 0.25 * z^-4------------------1 - z^-1In [1]: from audiolazy import z, Stream, maverageIn [2]: M = 5In [3]: media_movel_5 = (1 - z ** -M) / (M * (1 - z ** -1))In [4]: acumulador = 1 / (1 - z ** -1)In [5]: media_movel_5(Stream(5)).take(10)Out[5]: [1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]In [6]: acumulador(Stream(5)).take(10)Out[6]: [5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0]In [7]: maverage.recursive(4)Out[7]:0.25 - 0.25 * z^-4------------------1 - z^-1Filtros LTI, em geral:
  • 16. Filtros prontos!● Média móvel● Ressonadores● Comb● Passa-baixas e passa-altas● Gammatone (Patterson-Holdsworth, audição)– Slaney– Klapuri● 4 ressonadores em cascata– Implementação genérica (qualquer ordem)● Teoremas (parte de meu mestrado)Filtros variantes no tempo!Coeficientes “a” em de a * z ** -kpodem ser objetos Stream)
  • 17. Plot (AudioLazy + MatPlotLib)!● DTFT - Caso particular da transformada Z– O valor de z está na circunferência complexa unitária● Método plot dos filtros– Resposta em frequência● Método zplot– Estabilidade do filtro– Pólos: “X”● Raízes do denominador– Zeros: “O”● Raízes do numeradorXXMatPlotLibfaz melhorque isto...
  • 18. Considerações finais sobre filtros● Implementação direta I– Evita multiplicação por 1– Não cria os termos com coeficiente nulo● JIT (Just in Time)– Cada filtro é criado e compilado em tempo deexecução– Permite filtros variantes no tempo gerais e (até certoponto) eficientes
  • 19. Parte 4 - Cálculo numérico (e umpouco de simbólico também)Heeeeeey, não era sobre áudio?Heeeeeey, não era sobre áudio?
  • 20. Exemplos● Pi (exemplo no repositório da AudioLazy)– Série de Madhava-Gregory-Leibniz● Fibonacciatan(v)=v−v33+v55−v77+v99...atan(1)= π4In [2]: (z ** -1 / (1 - z ** -1 - z ** -2))(impulse()).take(10)Out[2]: [0.0, 1.0, 1.0, 2.0, 3.0, 5.0, 8.0, 13.0, 21.0, 34.0]In [2]: (z ** -1 / (1 - z ** -1 - z ** -2))(impulse()).take(10)Out[2]: [0.0, 1.0, 1.0, 2.0, 3.0, 5.0, 8.0, 13.0, 21.0, 34.0]h[n]=h[n−1]+h[ n−2]+δ[ n−1]
  • 21. 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ímbolosdo SymPy, etc.● Objeto “x”● Interpolação (polinômios de Lagrange)In [9]: lagrange.poly([(1, 3), (3, 14), (45, 0)])Out[9]: -2.89773 + 6.0303 * x - 0.132576 * x^2In [9]: lagrange.poly([(1, 3), (3, 14), (45, 0)])Out[9]: -2.89773 + 6.0303 * x - 0.132576 * x^2In [8]: (x + x ** 2 + x ** -.5)(4)Out[8]: 20.5In [8]: (x + x ** 2 + x ** -.5)(4)Out[8]: 20.5
  • 22. SymPyStream de símbolos
  • 23. Comparação de números em pontoflutuante (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 em um dicionário de estratégias:– almost_eq.diff– almost_eq ou almost_eq.bits∣a−b∣≤l∣a−b∣≤2(t − s−1)∣a+b∣
  • 24. Quantização em ponto flutuanteCom CascadeFilterWarning:Há textos que nem sempre são claros quanto aos aspectosnecessários à implementação para garantir a estabilidade numéricafreq = 100 * Hzbw = erb(freq, Hz) * gammatone_erb_constants(4)[0]filt = gammatone.slaney(freq, bw)filt.plot(rate=rate, freq_scale="log", samples=8192).show()freq = 100 * Hzbw = erb(freq, Hz) * gammatone_erb_constants(4)[0]filt = gammatone.slaney(freq, bw)filt.plot(rate=rate, freq_scale="log", samples=8192).show()Sem CascadeFilter
  • 25. Parte 5MIRMIR((Music Information RetrievalMusic Information Retrieval))
  • 26. Pitch – Shepard● Som de Shepard– Subir “sem parar”– Exemplo no GitHub● Duas dimensões:– Altura (pitch height)● Dimensão “linear”– Croma (pitch chroma)● Dimensão “circular”● Lembra Escher →
  • 27. 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 maiorfilt = 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 maiorfilt = 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
  • 28. ZCRTaxa de cruzamentos no zeroIn [15]: pitch1.take(10) # Resultado em HzOut[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 notasOut[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 HzOut[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 notasOut[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@tostreamdef 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))@tostreamdef 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()Por quenão DFT?
  • 29. AMDF (Average Magnitude DifferenceFunction)
  • 30. AutocorrelaçãoTranscrição por envoltória dinâmica
  • 31. Decomposição cromática● Filtros gammatone– Paralelo● OitavasIn [1]: from audiolazy import octavesIn [2]: octaves(440)Out[2]: [27.5, 55.0, 110.0, 220.0, 440, 880, 1760, 3520, 7040, 14080]In [1]: from audiolazy import octavesIn [2]: octaves(440)Out[2]: [27.5, 55.0, 110.0, 220.0, 440, 880, 1760, 3520, 7040, 14080]from __future__ import divisionfrom audiolazy import *def cromafb(classes=12, rate):s, Hz = sHz(rate)cg = gammatone_erb_constants(4)[0]fb = 440return [ParallelFilter(gammatone.sampled(f*Hz, cg*erb(f))for f in octaves(fb * 2**(n/classes))) for n in xrange(classes)]rate = 44100bank = cromafb(rate=rate)bank[0].plot(freq_scale="log", rate=rate)from __future__ import divisionfrom audiolazy import *def cromafb(classes=12, rate):s, Hz = sHz(rate)cg = gammatone_erb_constants(4)[0]fb = 440return [ParallelFilter(gammatone.sampled(f*Hz, cg*erb(f))for f in octaves(fb * 2**(n/classes))) for n in xrange(classes)]rate = 44100bank = cromafb(rate=rate)bank[0].plot(freq_scale="log", rate=rate)
  • 32. Cromagrama
  • 33. from audiolazy import *rate = 22050s, Hz = sHz(rate)size = 512table = 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 oitavafilt = lpc(data, order=14) # Filtro de análiseG = 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 = 22050s, Hz = sHz(rate)size = 512table = 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 oitavafilt = lpc(data, order=14) # Filtro de análiseG = 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 espectralLPC - Predição LinearFormantesPode serutilizado paraclassificaçãode vogais
  • 34. Parte 6NúcleoNúcleo(Não, não vai explodir...)(Não, não vai explodir...)
  • 35. AbstractOperatorOverloaderMeta● Metaclasse– Classe cujas instâncias são classes● Abstrata– Classe com recursos especificados porém semimplementação● Sobrecarga massiva de operadores:– Binários– Binários reversos– Unários● Utiliza-se da classe OpMethod– Organiza todos os 33 possíveis dunders de operadoresHá, entretanto, 35 no Python 2.AbstractOperatorOverloaderMetainsere __div__ e __rdiv__automaticamente a partir de__truediv__ e __rtruediv__(quando aplicável)
  • 36. Objeto windowUm dicionário de estratégiasIn [1]: from audiolazy import windowIn [2]: window # Vejamos as estratégias disponíveisOut[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 argumentoOut[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árioIn [6]: hm_wnd # Esta estratégia é uma função comumOut[6]: <function audiolazy.lazy_analysis.hamming>In [1]: from audiolazy import windowIn [2]: window # Vejamos as estratégias disponíveisOut[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 argumentoOut[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árioIn [6]: hm_wnd # Esta estratégia é uma função comumOut[6]: <function audiolazy.lazy_analysis.hamming>Também é um iterável porsuas estratégias(ver windows_plot.py)
  • 37. Documentação● Docstrings: documentação no código– Uso em ambientes interativos– reStructuredText– Organização em seções● Visualização no Spyder (Rich Text), IPython● Sphinx– Conversão automática do sistema de seções para o formato doSphinx– 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.http://pythonhosted.org/audiolazyhttps://github.com/danilobellini/audiolazy/tree/master/audiolazy/examples
  • 38. Parte 7FinalizaçãoFinalização
  • 39. 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– MultiplataformaSuporta Python 2 e 3 com omesmo código!
  • 40. Motivações e justificativasNo papel...● Demanda e insatisfação com código existente– Por mim● Vetores (NumPy, Octave/MatLab)...tempo real?● Índices...=(– Por outros● 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)!!! Bad guy...código?● Base para trabalhos futuros
  • 41. Resumidamente:The Litmus TestIf you have to refer to theIf you have to refer to thedocumentation every timedocumentation every timeyou use a module, find (oryou use a module, find (orbuild) a new module.build) a new module.Até tentei evitar...mas...
  • 42. 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% 72lazy_analysis 125 3 60 2 97% 211, 259-260lazy_auditory 60 0 14 0 100%lazy_compat 42 5 6 1 88% 43, 67-68, 78-79lazy_core 174 7 78 9 94% 124, 136-138, 346, 471, 478lazy_filters 509 179 245 117 61% 55, 62, 83, 93, [...]lazy_io 156 43 58 28 67% 89, 141-157, 161, [...]lazy_itertools 37 12 20 13 56% 38, 59-60, 69-74, 100-103lazy_lpc 128 15 42 7 87% 121, 135-136, [...]lazy_math 61 1 28 0 99% 133lazy_midi 54 5 26 3 90% 70, 111, 150, 156, 158lazy_misc 110 9 62 10 89% 156-157, 194, [...]lazy_poly 184 2 124 3 98% 387-388lazy_stream 175 2 76 4 98% 59, 738lazy_synth 243 32 118 39 80% 277-299, 428, 430, [...]lazy_text 104 16 70 18 80% 133-148, 207, [...]------------------------------------------------------------TOTAL 2206 332 1045 258 82%========================= 5938 passed in 29.00 seconds =========================--------------- coverage: platform linux2, python 2.7.3-final-0 ----------------Name Stmts Miss Branch BrPart Cover Missing------------------------------------------------------------__init__ 44 1 18 4 92% 72lazy_analysis 125 3 60 2 97% 211, 259-260lazy_auditory 60 0 14 0 100%lazy_compat 42 5 6 1 88% 43, 67-68, 78-79lazy_core 174 7 78 9 94% 124, 136-138, 346, 471, 478lazy_filters 509 179 245 117 61% 55, 62, 83, 93, [...]lazy_io 156 43 58 28 67% 89, 141-157, 161, [...]lazy_itertools 37 12 20 13 56% 38, 59-60, 69-74, 100-103lazy_lpc 128 15 42 7 87% 121, 135-136, [...]lazy_math 61 1 28 0 99% 133lazy_midi 54 5 26 3 90% 70, 111, 150, 156, 158lazy_misc 110 9 62 10 89% 156-157, 194, [...]lazy_poly 184 2 124 3 98% 387-388lazy_stream 175 2 76 4 98% 59, 738lazy_synth 243 32 118 39 80% 277-299, 428, 430, [...]lazy_text 104 16 70 18 80% 133-148, 207, [...]------------------------------------------------------------TOTAL 2206 332 1045 258 82%========================= 5938 passed in 29.00 seconds =========================Mock
  • 43. Testes com oráculos● 80 c/ o scipy.signal.lfilter● 64 c/ o subpacote de otimização do SciPy● 2 c/ o NumPyimport pytestp = pytest.mark.parametrizefrom scipy.signal import lfilterfrom audiolazy import ZFilter, almost_eqclass 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 AudioLazyexpected = lfilter(b, a, data).tolist() # Aplica o filtro com o SciPyassert almost_eq(filt(data), expected) # Compara os resultadosimport pytestp = pytest.mark.parametrizefrom scipy.signal import lfilterfrom audiolazy import ZFilter, almost_eqclass 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 AudioLazyexpected = lfilter(b, a, data).tolist() # Aplica o filtro com o SciPyassert almost_eq(filt(data), expected) # Compara os resultados
  • 44. 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
  • 45. Últimas novidades!● Python 3!● Contas com polinômios variantes no tempo● Métodos das classes Stream e StreamTeeHub– Peek– Skip– Limit● Polinômios de Lagrange (interpolação)● Reamostragem (taxa de amostragem variante notempo)– Isso é útil? (variante no tempo)
  • 46. Possíveis continuações para odesenvolvimento 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 notempo– Interpolação por splines– Frações parciais– Otimização– Escrita no tempo– SymPy– Treliça●Outros– Integrar com PureData– I/O MIDI– Plugins (e.g. Vamp)– Tutorial– Logo
  • 47. Obrigado!Perguntas?Perguntas?Fork me on GitHubFork me on GitHubhttps://github.com/danilobellini/audiolazyhttps://github.com/danilobellini/audiolazy