Transcript
  • 1. AudioLazy processamento de sinais para msica, jogos e muito mais! http://pypi.python.org/pypi/audiolazy Copyright (C) 2012-2013 Danilo de Jesus da Silva Bellini [email protected] @danilobelliniCentro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF

2. c/ Pyth o m on AudioLazy es 2e mo c 3 dig DSP (Digital Signal Processing) para udio o Anlise MIR (Music Information Retrieval) Sntese ProcessamentoExpressividade de cdigo Documentao (Sphinx)http://pythonhosted.org/audiolazyFacilita prototipao, simulaoTempo real (latncia de aproximadamente 35ms c/ o Jack) Possibilita uso em aplicaes finaisCentro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF! 3. Resultados cobertura de cdigo Orculos (Testes automatizados)(NumPy, SciPy)--------------- coverage: platform linux2, python 2.7.3-final-0 ------------------------------ coverage: platform linux2, python 2.7.3-final-0 ---------------Name Stmts Miss Branch BrPart Cover Missing Name Stmts Miss Branch BrPart Cover Missing ----------------------------------------------------------------------------------------------------------------------Mock __init__ 44 1 18 4 92% 72 __init__ 44 1 18 4 92% 72 lazy_analysis 125 3 60 2 97% 211, 259-260 lazy_analysis 125 3 60 2 97% 211, 259-260 lazy_auditory 60 0 14 0 100% lazy_auditory 60 0 14 0 100% lazy_compat 42 5 6 1 88% 43, 67-68, 78-79 lazy_compat 42 5 6 1 88% 43, 67-68, 78-79 lazy_core 175 7 80 9 94% 124, 136-138, 346, 471, 478 lazy_core 175 7 80 9 94% 124, 136-138, 346, 471, 478 lazy_filters 521 176 247 115 62% 57, 64, 85, 95, [...] lazy_filters 521 176 247 115 62% 57, 64, 85, 95, [...] lazy_io 156 43 58 28 67% 89, 141-157, 161, [...] lazy_io 156 43 58 28 67% 89, 141-157, 161, [...] lazy_itertools 41 7 20 11 70% 39, 60-61, 66, 108-111 lazy_itertools 41 7 20 11 70% 39, 60-61, 66, 108-111 lazy_lpc 128 15 42 7 87% 121, 135-136, [...] lazy_lpc 128 15 42 7 87% 121, 135-136, [...] lazy_math 61 1 28 0 99% 133 lazy_math 61 1 28 0 99% 133 lazy_midi 54 5 26 3 90% 70, 111, 150, 156, 158 lazy_midi 54 5 26 3 90% 70, 111, 150, 156, 158 lazy_misc 110 9 62 10 89% 156-157, 194, [...] lazy_misc 110 9 62 10 89% 156-157, 194, [...] lazy_poly 191 2 126 3 98% 396-397 lazy_poly 191 2 126 3 98% 396-397 lazy_stream 175 2 76 4 98% 59, 738 lazy_stream 175 2 76 4 98% 59, 738 lazy_synth 251 32 124 40 81% 278-300, 467, 469, [...] lazy_synth 251 32 124 40 81% 278-300, 467, 469, [...] lazy_text 102 33 70 29 64% 132-147, 205-229, [...] lazy_text 102 33 70 29 64% 132-147, 205-229, [...] ----------------------------------------------------------------------------------------------------------------------TOTAL 2236 341 1057 266 82% TOTAL 2236 341 1057 266 82% ========================= 2310 passed in 22.36 seconds ========================= ========================= 2310 passed in 22.36 seconds =========================Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 4. Parte 1 SnteseGo go go! No, Python!Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 5. Hello world em udio Tocar uma senide Consolefrom audiolazy import * from audiolazy import *(e.g. IPython)rate = 44100 rate = 44100 s, Hz = sHz(rate) s, Hz = sHz(rate)Multith reaplayer = AudioIO() player = AudioIO() snd = sinusoid(440 * Hz).limit(2 snd = sinusoid(440 * Hz).limit(2 th = player.play(snd, rate=rate) th = player.play(snd, rate=rate)* * # #d!s) s) an AudioThread an AudioThreadplayer.close() # Kill th (AudioIO arg isn't true) player.close() # Kill th (AudioIO arg isn't true)Scripts podem usar gerenciadores de contexto with AudioIO(True) as player: # Wait threads with AudioIO(True) as player: # Wait threads player.play(snd, rate=rate) player.play(snd, rate=rate)Dados rate, s, Hz, AudioIO e sinusoid: AudioIO(True).play(sinusoid(440 * Hz).limit(2 * s), rate=rate) AudioIO(True).play(sinusoid(440 * Hz).limit(2 * s), rate=rate)Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 6. Notas/Alturas e MIDI Pitch Notas/alturas D = RE = MiF = FA = LB = SiMIDI Pitch str2freqCb4 (d bemol) a mesma nota que B3freq2strIgnoram a alteraostr2midiIniciam em dmidi2strOitavas Todas as combinaesG = SolC = Dmidi2freqfreq2midiDefine 69 como A4 (l central), deslocamento em semitonsCentro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 7. Controle e tipos de sntese Ex ControlStream em plo Property value s!! wx Permite interatividade ! Py Tempo real Mu tho Sntese sic n, Aditiva (e.g. classe TableLookup) 21 Modulao Ring Modulation (Anel) AM (Amplitude) Senide * (1 + Senide)FM (Frequncia ou fase) Senide * SenideSenide(Senide)Subtrativa (e.g. modelo de Karplus-Strong)Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DFImagem da Wikipedia 8. Parte 2 RepresentaoCentro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 9. Container para udio Tempo real Amostras (dados/elementos) inexistentes... ...em tempo de compilao (dados a serem coletados) ...em tempo de execuo (dados criados no futuro)Durao possivelmente indefinida (endless)No deve ser necessrio computar tudo para comear a apresentar o resultado Resultados parciais Para cada amostra de entrada, deve haver uma de sada Minimizar lag (atraso) entre entrada e sadaLaziness! Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 10. Classe Stream In [1]: data = Stream(range(7)) In [1]: data = Stream(range(7)) ItervelIn [2]: blks = data.blocks(size=3, hop=2) In [2]: blks = data.blocks(size=3, hop=2)HeterogneoIn [3]: [list(blk) for blk in blks] In [3]: [list(blk) for blk in blks] Out[3]: [[0, 1, 2], [2, 3, 4], [4, 5, 6]] Out[3]: [[0, 1, 2], [2, 3, 4], [4, 5, 6]]Lazy! (Avaliao tardia)Operadores (Elementwise/broadcast)Mtodos (take, peek, limit, skip, map, filter, blocks) In In In In In In[1]: [1]: [2]: [2]: [3]: [3]:from audiolazy import Stream, inf from audiolazy import Stream, inf dados = Stream(5, 7, 1, 2, 5, 3, 2) # Peridico dados = Stream(5, 7, 1, 2, 5, 3, 2) # Peridico dados2 = Stream(0, 1) # Idem dados2 = Stream(0, 1) # IdemIn [4]: In [4]: Out[4]: Out[4]:(dados (dados [5, 8, [5, 8,In [5]: In [5]: Out[5]: Out[5]:(_ * Stream(1 + 2j, -3j, 7).imag).map(int).take(inf) (_ * Stream(1 + 2j, -3j, 7).imag).map(int).take(inf) [2.0, 0.0, 14] [2.0, 0.0, 14]Centro de Convenes Ulysses Guimares+ dados2).take(15) + dados2).take(15) 1, 3, 5, 4, 2, 6, 7, 2, 2, 6, 3, 3, 5] 1, 3, 5, 4, 2, 6, 7, 2, 2, 6, 3, 3, 5]AudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 11. Parte 3Filtros digitais e a Transformada ZCentro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 12. Filtros LTI (Lineares e invariantes no tempo) Digital signal processing is mainly based on linear time-invariant systems. systems. (Dutilleux, Dempwolf, Holters e Zlzer DAFx, segunda edio, captulo 4, p. 103) Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 13. Transformada Z Definio:Interpretao:Atraso em k amostras!In [1]: from audiolazy import z, inf In [1]: from audiolazy import z, inf In [2]: sig = [1, 2, 3, 4, 5, 6, 7] In [2]: sig = [1, 2, 3, 4, 5, 6, 7] In [3]: In [3]: Out[3]: Out[3]:(z ** (z ** [0.0, [0.0,-2)(sig).take(inf) -2)(sig).take(inf) 0.0, 1, 2, 3, 4, 5] 0.0, 1, 2, 3, 4, 5]In [4]: In [4]: Out[4]: Out[4]:(1 - z ** -2)(sig).take(inf) (1 - z ** -2)(sig).take(inf) [1.0, 2.0, 2, 2, 2, 2, 2] [1.0, 2.0, 2, 2, 2, 2, 2]Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 14. Objeto z In [1]: from audiolazy import z, Stream, maverage In [1]: from audiolazy import z, Stream, maverage In [2]: M = 5 In [2]: M = 5 In [3]: media_movel_5 = (1 - z ** -M) / (M * (1 - z ** -1)) In [3]: media_movel_5 = (1 - z ** -M) / (M * (1 - z ** -1)) In [4]: acumulador = 1 / (1 - z ** -1) In [4]: acumulador = 1 / (1 - z ** -1) In [5]: In [5]: Out[5]: Out[5]:media_movel_5(Stream(5)).take(10) media_movel_5(Stream(5)).take(10) [1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0] [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) 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] 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) In [7]: maverage.recursive(4) Out[7]: Out[7]: 0.25 - 0.25 * z^-4 0.25 - 0.25 * z^-4 ----------------------------------1 - z^-1 1 - z^-1Filtros LTI, em geral:Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 15. Filtros prontos! JIT!Filtr Coe os varia Mdia mvel ntes parc ficien no t tes ( elas Ressonadores e mp fato a * r o obje z ** -k es a e ! Comb tos S ) po m trea dem s Passa-baixas e passa-altas m) er Gammatone (Patterson-Holdsworth, audio) SlaneyKlapuri 4 ressonadores em cascataImplementao genrica (qualquer ordem) Teoremas (parte de meu mestrado)Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 16. Plot (AudioLazy + MatPlotLib)! DTFT - Caso particular da transformada Z Mtodo plot dos filtros O valor de z est na circunferncia complexa unitria Resposta em frequnciaMtodo zplot Estabilidade do filtroXPlos: X Razes do denominadorZeros: O XRazes do numeradorCentro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DFMatPlotLib faz melhor que isto... 17. Parte 4 Aplicaes inusitadasClculo numrico Gerao de imagensCentro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 18. Pi! Exemplo no repositrio da AudioLazySrie de Madhava-Gregory-Leibniz 3579v v v v atan (v)=v + + ... 3 5 7 9 atan(1)= 4Frmula de Machin =atan 1 + atan 1 4 5 239()Centro de Convenes Ulysses Guimares( )AudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 19. Fibonacci h[0] = 0h[1] = 1h[n] = h[n-1] + h[n-2] Pode-se interpretar como [0, 1, 0, 0, 0, 0, ...] aplicado ao filtro digital com esta equaoimpulse() o itervel [1, 0, 0, 0, 0, ]h [n]=h[n1]+ h[ n2]+ [ n1] In [2]: In [2]: Out[2]: Out[2]:(z ** -1 / (1 (z ** -1 / (1 [0, 1, 1, 2, 3, [0, 1, 1, 2, 3,Centro de Convenes Ulysses Guimaresz ** -1 z ** -1 5, 8, 13, 5, 8, 13,z ** -2))(impulse()).map(int).take(16) z ** -2))(impulse()).map(int).take(16) 21, 34, 55, 89, 144, 233, 377, 610] 21, 34, 55, 89, 144, 233, 377, 610]AudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 20. Polinmios Baseados em dicionrioIn [7]: (x + x ** 2 + x ** -.5)(4) In [7]: (x + x ** 2 + x ** -.5)(4) Out[7]: 20.5 Out[7]: 20.5MemriaExpoente negativo (Laurent)Expoente fracionrio (soma de potncias)Objeto xInterpolao LagrangeIn [9]: In [9]: Out[9]: Out[9]:lagrange.poly([(0, 0), (1, 1)]) lagrange.poly([(0, 0), (1, 1)]) x xIn [10]: lagrange.poly([(0, 0), (1, 1), (2, 2)]) In [10]: lagrange.poly([(0, 0), (1, 1), (2, 2)]) Out[10]: x Out[10]: x In [11]: lagrange.poly([(0, 0), (1, 1), (2, 4)]) In [11]: lagrange.poly([(0, 0), (1, 1), (2, 4)]) Out[11]: x^2 Out[11]: x^2 In [9]: lagrange.poly([(1, 3), (3, 14), (45, 0)]) In [9]: lagrange.poly([(1, 3), (3, 14), (45, 0)]) Out[9]: -2.89773 + 6.0303 * x - 0.132576 * x^2 Out[9]: -2.89773 + 6.0303 * x - 0.132576 * x^2Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 21. Gerao de imagensCentro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 22. Parte 5MIR (Music Information Retrieval) Retrieval)Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 23. Pitch Shepard Som de Shepard Subir sem parar Exemplo no GitHubDuas dimenses: Altura (pitch height) Dimenso linearCroma (pitch chroma) Dimenso circular Lembra Escher Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 24. Srie harmnica F0, 2F0, 3F0, 4F0 100 Hz, 200 Hz, 300 Hz...Inteiros? Racionais? Primos? 2+ oitavaComb!freqs = [str2freq(note) for note in "E2 G#2 B2".split()] # Mi maior freqs = [str2freq(note) for note in "E2 G#2 B2".split()] # Mi maior filt = ParallelFilter(comb.tau(freq_to_lag(freq * Hz), .1 * s) filt = ParallelFilter(comb.tau(freq_to_lag(freq * Hz), .1 * s) for freq in freqs) for freq in freqs) Centro de Convenes AudioLazy Danilo J. S. Bellini @danilobellini filt.plot(samples=8192, rate=rate, min_freq=220*Hz, max_freq=880*Hz).show() filt.plot(samples=8192, rate=rate, min_freq=220*Hz, max_freq=880*Hz).show() Ulysses GuimaresUlysses Guimares2013-10-03 Braslia DF 25. ZCR Taxa de cruzamentos no zero In [15]: pitch1.take(10) # Resultado em Hz In [15]: pitch1.take(10) # Resultado em Hz Out[15]: Out[15]: [872.0947265625001, [872.0947265625001, 882.861328125, 882.861328125, data1 = .5 * sinusoid(880 * Hz) data1 = .5 * sinusoid(880 * Hz) 872.0947265625001, 872.0947265625001, data1 += .5 * saw_table(880*3 * Hz) data1 += .5 * saw_table(880*3 * Hz) 882.861328125, 882.861328125, data1 *= .9 + .1 * white_noise() data1 *= .9 + .1 * white_noise() 882.861328125, 882.861328125, 882.861328125, 882.861328125, 882.861328125, 882.861328125, 872.0947265625001, 872.0947265625001, pitch1 = zcross_pitch(data1) / Hz pitch1 = zcross_pitch(data1) / Hz 882.861328125, 882.861328125, 872.0947265625001] 872.0947265625001]Por no que DFT ?In [16]: freq2str(pitch1).take(10) # Resultado em nomes de notas In [16]: freq2str(pitch1).take(10) # Resultado em nomes de notas Out[16]: Out[16]: ['A5+5.62%', ['A5+5.62%', 'A5+5.62%', 'A5+5.62%', 'A5+5.62%', 'A5+5.62%', @tostream @tostream 'A5+5.62%', 'A5+5.62%', def zcross_pitch(sig, size=2048): def zcross_pitch(sig, size=2048): 'A5+5.62%', 'A5+5.62%', "Devolve a altura em cada bloco com o dado tamanho" "Devolve a altura em cada bloco com o dado tamanho" 'A5-15.62%', 'A5-15.62%', for blk in zcross(sig, hysteresis=.2).blocks(size): for blk in zcross(sig, hysteresis=.2).blocks(size): 'A5+5.62%', 'A5+5.62%', yield lag_to_freq(2. * size / sum(blk)) yield lag_to_freq(2. * size / sum(blk)) 'A5-15.62%', 'A5-15.62%', 'A5+5.62%', 'A5+5.62%', Centro de Convenes AudioLazy Danilo J. S. Bellini @danilobellini 'A5+5.62%'] 'A5+5.62%']Ulysses Guimares2013-10-03 Braslia DF 26. AMDF (Average Magnitude Difference Function)Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 27. Autocorrelao Transcrio por envoltria dinmicaCentro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 28. Decomposio cromtica from __future__ import division from __future__ import division from audiolazy import * from audiolazy import * def cromafb(classes=12, rate): def cromafb(classes=12, rate): s, Hz = sHz(rate) s, Hz = sHz(rate) cg = gammatone_erb_constants(4)[0] cg = gammatone_erb_constants(4)[0] fb = 440 fb = 440 return [ return [ ParallelFilter( ParallelFilter( gammatone.sampled(f*Hz, cg*erb(f)) gammatone.sampled(f*Hz, cg*erb(f)) for f in octaves(fb * 2**(n/classes)) for f in octaves(fb * 2**(n/classes)) ) for n in xrange(classes) ) for n in xrange(classes) ] ] Filtros gammatone Paralelorate = 44100 rate = 44100 bank = cromafb(rate=rate) bank = cromafb(rate=rate) bank[0].plot(freq_scale="log", rate=rate) bank[0].plot(freq_scale="log", rate=rate)Oitavas In [1]: from audiolazy import octaves In [1]: from audiolazy import octavesIn [2]: octaves(440) In [2]: octaves(440) Centro de Convenes AudioLazy Danilo J. S. Bellini @danilobellini Out[2]: [27.5, 55.0, 110.0, 220.0, 440, 880, 1760, 3520, 7040, 14080] Out[2]: [27.5, 55.0, 110.0, 220.0, 440, 880, 1760, 3520, 7040, 14080] Ulysses Guimares 2013-10-03 Braslia DF 29. CromagramaCentro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 30. Envoltria espectral LPC - Predio LinearFormantes Pode ser utilizado para classificao de vogais from audiolazy import * from audiolazy import *rate = 22050 rate = 22050 s, Hz = sHz(rate) s, Hz = sHz(rate) size = 512 size = 512 table = sin_table.harmonize({1: 1, 2: 5, 3: 3, 4: 2, 6: 9, 8: 1}).normalize() table = sin_table.harmonize({1: 1, 2: 5, 3: 3, 4: 2, 6: 9, 8: 1}).normalize() data = table(str2freq("Bb3") data = table(str2freq("Bb3") filt = lpc(data, order=14) # filt = lpc(data, order=14) # G = 1e-2 # Ganho apenas para G = 1e-2 # Ganho apenas para* Hz).take(size) # Nota si bemol da 3a oitava * Hz).take(size) # Nota si bemol da 3a oitava Filtro de anlise Filtro de anlise alinhamento na visualizao com a DFT alinhamento na visualizao com a DFT# Filtro de sntese AudioLazy Danilo J. S. Bellini @danilobellini # Filtro de sntese Centro de Convenes (G / filt).plot(blk=data, rate=rate, samples=1024,DF (G / filt).plot(blk=data, rate=rate, samples=1024, unwrap=False).show() Ulysses Guimares 2013-10-03 Braslia unwrap=False).show() 31. Parte 6FinalizaoCentro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 32. Situao atual e futuro da AudioLazy Verso 0.05 (ltima zero-zero) Compatibilidade entre Python 2 e 3! Embora o MatPlotLib e o py.test sejam mais lento no Python 3, no o caso c/ a AudioLazyExemplos prticos, refactoring, polinmiosFuturo (verso 0.1) Sync para I/O (evita caching no Linux)Personalizao do AudioIO (dispositivo no padro) Filtros com expoentes inteiros variantes no tempoOtimizao para filtros combProjetos em desenvolvimento utilizando ou planejando utilizar a AudioLazy Sintetizador, pedaleira, jogos, 676 downloads realizados no ltimo ms PyPI, valor coletado dia 2013-10-03Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 33. Possveis continuaes para o desenvolvimento da AudioLazy AnliseHeursticas, MIR featuresPlugins (Vamp)Modelagem audio Mock MatPlotLibFiltrosOutros modelos (Lyon, Seneff, gamma chirp, etc.)Fraes parciaisEscrita no tempo (linear e no-linear) e.g. y[n] = x[n] + x[n -1] * x[n - 2]SymPy (coeficientes e sinais simblicos)Wah, phaser, eco, compressor, noise gate, Implementaes alternativasHost de plugins LADSPAI/OFlanger Karplus-Strong variante no tempoExemplos de uso da AudioLazyIntegrar com PureData, CSound, etc.Atrasos/expoentes fracionrios variantes no tempo Converso entre x-dB e ERBChegar aos 100%Sntese e processamento Testes Trelia Forma direta IIOutros LogoMIDIFormatao da documentao (Sphinx)Integrar com PyGameOtimizaoCentro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF 34. Obrigado! Perguntas?Fork me on GitHub https://github.com/danilobellini/audiolazy Centro de Convenes Ulysses GuimaresAudioLazy Danilo J. S. Bellini @danilobellini 2013-10-03 Braslia DF


Top Related