Your SlideShare is downloading. ×
(2013-05-03) AudioLazy - Slides
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

(2013-05-03) AudioLazy - Slides

608
views

Published on

Slides baseados na defesa de mestrado ocorrida no dia anterior, com algumas correções.

Slides baseados na defesa de mestrado ocorrida no dia anterior, com algumas correções.

Published in: Technology

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
608
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
12
Comments
0
Likes
2
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. AudioLazyDSP (DSP (Digital Signal ProcessingDigital Signal Processing) expressivo e) expressivo eem tempo real para o Pythonem tempo real para o PythonProjeto open source (GPLv3)Projeto open source (GPLv3)http://pypi.python.org/pypi/audiolazyhttp://pypi.python.org/pypi/audiolazyCopyright (C) 2012-2013Copyright (C) 2012-2013Danilo de Jesus da Silva BelliniDanilo de Jesus da Silva Bellinidanilo [dot] bellini [at] gmail [dot] comdanilo [dot] bellini [at] gmail [dot] com
  • 2. Parte 1Aspectos geraisAspectos gerais
  • 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. LinguagemCritério MatLab Octave PureData Python NumPyAmostras Sim Sim Depende Sim SimBlocos Possível Possível Sim Possível PossívelÁlgebra linear Sim Sim Depende Possível SimDSP Sim Sim Sim Possível SimTempo real Não Não Sim Possível NãoHeterogeneidade Não Não Não Sim PossívelAvaliação tardia Não Não Depende Sim NãoFunções de ordemsuperiorNão Não Não Sim NãoOrientação a objetos Possível Possível Não Sim SimLinguagem de usogeralNão Não Não Sim SimDocumentação Sim Sim Sim Sim SimLicença Proprietária GNU GPLBSDModificadaPSFL BSDPreço US$99.00 Gratuito Gratuito Gratuito GratuitoCódigo fonte (Fechado) C++ C C, PythonC, Fortran,Python
  • 6. Outras linguagens● CAS (ComputerAlgebra System)– Wolfram Mathematica– SymPy● C, C++, Java– Estáticas– Imperativo– S/ ênfase em serexpressivo● DSL (Domain SpecificLanguage)– 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% 72lazy_analysis 124 3 62 4 96% 210, 258-259lazy_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-64lazy_lpc 127 15 42 7 87% 120, 134-135, [...]lazy_math 59 1 28 0 99% 131lazy_midi 54 5 26 3 90% 70, 111, 150, 156, 158lazy_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, 606lazy_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% 72lazy_analysis 124 3 62 4 96% 210, 258-259lazy_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-64lazy_lpc 127 15 42 7 87% 120, 134-135, [...]lazy_math 59 1 28 0 99% 131lazy_midi 54 5 26 3 90% 70, 111, 150, 156, 158lazy_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, 606lazy_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 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
  • 9. 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 na audiolazy.lazy_misc– almost_eq_diff– almost_eq∣a−b∣≤l∣a−b∣≤2(t − s−1)∣a+b∣
  • 10. Parte 2Síntese e processamento em tempo realSíntese e processamento em tempo real
  • 11. “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!
  • 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 coraisde J. S. Bach (Music21)● Personalizada– Construtor da classeStream– Decorador tostream
  • 13. Parte 3StreamStream
  • 14. Armazenamento: Estratégias paraavaliaçã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çãoIn [1]: def gerador_123():...: val = 1...: while True:...: yield val...: val = val + 1 if val < 3 else 1...:In [2]: gerador_123Out[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_123Out[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]: 1In [6]: sinal.next()Out[6]: 2In [7]: sinal.next()Out[7]: 3In [8]: sinal.next()Out[8]: 1In [4]: sinal = gerador_123()In [5]: sinal.next()Out[5]: 1In [6]: sinal.next()Out[6]: 2In [7]: sinal.next()Out[7]: 3In [8]: sinal.next()Out[8]: 1Desempenho!
  • 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 emtempo de compilação– Duração indefinida– Não é necessário computar tudo para começar aapresentar o resultadoAvaliação tardia!
  • 17. Classe Stream● Representa fluxo de informação (áudio)● Iterável heterogêneo com operadores (baseado noNumPy) e avaliação tardia● Ausência de índices– Limite de representação inteira (32 bits estouraria em27: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]
  • 18. Classe Stream● Métodos, atributos e propriedades são aplicadoselemento a elemento– Exceto “take”, “blocks” e outros da própria classeStream● 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]
  • 19. Decorador tostream:Geradores convertidos em Stream● Função = Decorador(Função)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]
  • 20. 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])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
  • 22. Parte 4FiltrosFiltros
  • 23. 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)
  • 24. Ressonador com valor exato
  • 25. Gammatone● Três modelos– Slaney– Klapuri● 4 ressonadores em cascata– Implementação genérica (qualquer ordem)● Teoremas
  • 26. Derivadas● Prova por indução
  • 27. Parte 5MIRMIR((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 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
  • 30. 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()
  • 31. AMDF (Average Magnitude DifferenceFunction)
  • 32. Ainda sobre frequência fundamental eperiodicidade ...● SDF (Square Difference Function)● ACF (Autocorrelação)– Inverso à AMDF e SDF (aqui queremos o maior valor)● MPM (McLeod e Wyvill)– Utilizar ACF para “normalizar” SDFDFT ?!?
  • 33. AutocorrelaçãoTranscrição por envoltória dinâmica
  • 34. Transformada discreta de Hilbert
  • 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 fundamentaiswhite_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 pelomenos uma nota● Sem otimizaçõesEntrada “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 = 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 Linear
  • 41. 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)
  • 42. Cromagrama
  • 43. Diferenciação
  • 44. Parte 6Aspectos de ImplementaçãoAspectos de Implementação
  • 45. 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
  • 46. 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>
  • 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ímbolosdo 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 deexecução– Permite filtros variantes no tempo gerais e eficientes
  • 49. Quantização em ponto flutuante
  • 50. MódulosNome Descriçãolazy_analysis Análise de áudiolazy_auditory Modelagem do aparato auditivo humano periféricolazy_core Núcleo com as três classes de fundamentação do pacotelazy_filters Filtroslazy_io Gravação e reprodução de áudio (via PyAudio), multi-threadlazy_itertools Conteúdo da itertools “decorado” ou adaptado para objetos Streamlazy_lpc Codificação linear preditiva (LPC)lazy_math Funções matemáticas para uso em iteráveis com manutenção de tipolazy_midi Representação MIDI e relações entre nota e frequência (altura)lazy_misc Diversas ferramentas de uso geral e constanteslazy_poly Polinômioslazy_stream Definição da classe Stream e derivadaslazy_synth Pequeno sintetizador
  • 51. ClassesNome Bases (herança) Módulo DescriçãoAudioIO object lazy_io Reprodutor/gravador de áudioAudioThread threading.Thread lazy_io Thread representando objetos sendo reproduzidosLinearFilterProperties object lazy_filters Mixin com conversores de propriedades de filtros linearesLinearFilter LinearFilterProperties lazy_filters Filtro linearZFilter LinearFilter lazy_filters Filtro linear representado por equações em ZFilterList list, LinearFilterProperties lazy_filters Lista de filtrosCascadeFilter FilterList lazy_filters Filtros em cascataParallelFilter FilterList lazy_filters Filtros em paraleloPoly object lazy_poly Polinômios, polinômios de Laurent, soma de potênciasTableLookup object lazy_synth Sintetizador por consulta à tabelaMultiKeyDict dict lazy_core Dicionário multi-chaveStrategyDict MultiKeyDict lazy_core Dicionário de estratégiasStrategyDictInstance StrategyDict lazy_core Uma classe para cada dicionário de estratégiasStream collections.Iterable lazy_stream Iterável com operadores elemento a elemento e avaliação tardiaControlStream Stream lazy_stream Stream que devolve um valor controlável, permitindointeratividadeStreamix Stream lazy_stream Misturador (mixer) de objetos Stream baseado na temporizaçãodo MIDIStreamTeeHub Stream lazy_stream Gerenciador de cópias de StreamMemoryLeakWarning Warning lazy_stream Número de usos de um StreamTeeHub menor que o especificadoParCorError 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 presentesna AudioLazyNome Estratégias Módulo Descriçãowindow 6 lazy_analysis Funções de janelamento ouapodizaçãoenvelope 3 lazy_analysis Filtros de obtenção de envoltóriadinâmicamaverage 3 lazy_analysis Criador de filtros de média móvelerb 2 lazy_auditory Largura de banda equivalenteretangular (ERB)gammatone 3 lazy_auditory Filtros gammatonecomb 3 lazy_filters Filtros combresonator 4 lazy_filters Ressonadoreslowpass 2 lazy_filters Passa-baixashighpass 1 lazy_filters Passa-altaslpc 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 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.
  • 55. Exemplos de implementação de partesda AudioLazydef levinson_durbin(acdata, order):def inner(a, b):return sum(acdata[abs(i-j)] * ai * bjfor 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 ** -mA -= inner(A, z ** -m) / inner(B, B) * Breturn Adef levinson_durbin(acdata, order):def inner(a, b):return sum(acdata[abs(i-j)] * ai * bjfor 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 ** -mA -= inner(A, z ** -m) / inner(B, B) * Breturn A
  • 56. Parte 7FinalizaçãoFinalização
  • 57. Situação atual (PyPI)VersãoDownloads(2013-02-15)Downloads(2013-05-01)0.01 432 7070.02 432 7090.03 209 4910.04 Não existia 328Valoresmí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 PyPyAudioLazy 271.49 ms 57.98 ms 53.24 msNumPy 19.45 ms 22.78 ms 21.06 msBenchmark: Síntese FM
  • 60. 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 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 GitHubhttps://github.com/danilobellini/audiolazyhttps://github.com/danilobellini/audiolazy