(2013-10-16) [LatinoWare] Processamento de sinais em Python

Embed Size (px)

Citation preview

Processamento de sinais em Python

Uma introduo com nfase em aplicaes em udio

Danilo de Jesus da Silva Bellini (AudioLazy Developer)danilo.bellini [at] gmail.com Twitter: @danilobellinihttps://pypi.python.org/pypi/audiolazy

AudioLazy

DSP (Digital Signal Processing) para udioAnliseMIR (Music Information Retrieval)

Sntese

Processamento

Expressividade de cdigoFacilita prototipao, simulao

Tempo real (latncia de aproximadamente 35ms c/ o Jack)Possibilita uso em aplicaes finais

Python 2 e 3c/ o mesmo cdigo!

Documentao (Sphinx)http://pythonhosted.org/audiolazy

Resultados cobertura de cdigo
(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 175 7 80 9 94% 124, 136-138, 346, 471, 478lazy_filters 521 176 247 115 62% 57, 64, 85, 95, [...]lazy_io 156 43 58 28 67% 89, 141-157, 161, [...]lazy_itertools 41 7 20 11 70% 39, 60-61, 66, 108-111lazy_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 191 2 126 3 98% 396-397lazy_stream 175 2 76 4 98% 59, 738lazy_synth 251 32 124 40 81% 278-300, 467, 469, [...]lazy_text 102 33 70 29 64% 132-147, 205-229, [...]------------------------------------------------------------TOTAL 2236 341 1057 266 82%

========================= 2310 passed in 22.36 seconds =========================

Mock

Orculos(NumPy, SciPy)

Parte 1
Como funciona um teclado sintetizador?

Talk is cheap.Show me the code.

(Linus Torvalds)

Hello world em udio

Tocar uma senideConsole(e.g. IPython)

ScriptsGerenciadores de contexto

from audiolazy import *

rate = 44100s, Hz = sHz(rate)

player = AudioIO()snd = sinusoid(440 * Hz).limit(2 * s)th = player.play(snd, rate=rate) # an AudioThread

player.close() # Kill th (AudioIO arg isn't true)

with AudioIO(True) as player: # Wait threads player.play(snd, rate=rate)

Multithread!

Notas/Alturas e MIDI Pitch

Pitch (notas/alturas)C = D

D = R

E = Mi

F = F

G = Sol

A = L

B = Si

OitavasIniciam em d

Ignoram a alteraoCb4 (d bemol) a mesma nota que B3

MIDI PitchDefine 69 como A4 (l central), deslocamento em semitons

Funes para realizar conversesmidi2str

str2midi

freq2str

str2freq

midi2freq

freq2midi

Controle e tipos de sntese

ControlStreamProperty value

Permite interatividadeTempo real

SnteseAditiva (e.g. classe TableLookup)

ModulaoRing Modulation (Anel)Senide * Senide

AM (Amplitude)Senide * (1 + Senide)

FM (Frequncia ou fase)Senide(Senide)

Subtrativa (e.g. modelo de Karplus-Strong)

Exemplos!!!getch, tkinter,wxPython, music21

In [1]: data = ControlStream(42)

In [2]: data.take(5)Out[2]: [42, 42, 42, 42, 42]

In [3]: data.value = -1

In [4]: data.take(5)Out[4]: [-1, -1, -1, -1, -1]

Parte 2
Funcionamento do altofalante e Representao do udio

Container para udio

Tempo realAmostras (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 resultadoResultados parciais

Para cada amostra de entrada, deve haver uma de sadaMinimizar lag (atraso) entre entrada e sada

Laziness!

Ocorre em udio e em vdeos, mas no em imagens estticas

Classe Stream

Itervel

Heterogneo

Lazy! (Avaliao tardia)

Operadores (Elementwise/broadcast)

Mtodos (take, peek, limit, skip, map, filter, blocks)

In [1]: from audiolazy import Stream, infIn [2]: dados = Stream(5, 7, 1, 2, 5, 3, 2) # PeridicoIn [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 [5]: (_ * Stream(1 + 2j, -3j, 7).imag).map(int).take(inf)Out[5]: [2.0, 0.0, 14]

In [1]: data = Stream(range(7))

In [2]: blks = data.blocks(size=3, hop=2)

In [3]: [list(blk) for blk in blks]Out[3]: [[0, 1, 2], [2, 3, 4], [4, 5, 6]]

Parte 3
Efeito wah, knob guitarra, transies

Filtros digitais e a Transformada Z

Filtros LTI
(Lineares e invariantes no tempo)

Digital signal processing is mainly based on linear time-invariant systems.

(Dutilleux, Dempwolf, Holters e ZlzerDAFx, segunda edio, captulo 4, p. 103)

Transformada Z

Definio:

Interpretao:Atraso em k amostras!

In [1]: from audiolazy import z, inf

In [2]: sig = [1, 2, 3, 4, 5, 6, 7]

In [3]: (z ** -2)(sig).take(inf)Out[3]: [0.0, 0.0, 1, 2, 3, 4, 5]

In [4]: (1 - z ** -2)(sig).take(inf)Out[4]: [1.0, 2.0, 2, 2, 2, 2, 2]

Objeto z

In [1]: from audiolazy import z, Stream, maverage

In [2]: M = 5

In [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^-1

Filtros LTI, em geral:

Filtros prontos!

AudioLazyMdia mvel

Ressonadores

Comb

Passa-baixas

Passa-altas

Gammatone (Patterson-Holdsworth, audio)

Scipy.signalButterworth

Chebyshev

Elptico

Filtros variantes no tempo!Coeficientes (fatores a em parcelas a * z ** -k) podem ser objetos Stream)

JIT!

Plot (AudioLazy + MatPlotLib)!

DTFT - Caso particular da transformada ZO valor de z est na circunferncia complexa unitria

Mtodo plot dos filtrosResposta em frequncia

Mtodo zplotEstabilidade do filtro

Plos: XRazes do denominador

Zeros: ORazes do numerador

X

X

Parte 4
Anlise

MIR(Music Information Retrieval)

O que altura / pitch?Como um afinador de guitarra funciona?

Pitch Shepard

Exemplo no GitHub

Cientista prope dividir o pitch em duas dimenses:Altura (pitch height)Dimenso linear

Croma (pitch chroma)Dimenso circular

Lembra Escher

Hlice

Srie harmnica

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()

Inteiros?Racionais?Primos?2+oitava

Coletando a altura

ZCR (Taxa de cruzamento no zero)

DFT (Transformada Discreta de Fourier)

AMDF (Average Magnitude Difference Function)

Autocorrelao (numpy.correlate)
Transcrio por envoltria dinmica

Decomposio cromtica

Filtros gammatoneParalelo

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]

from __future__ import divisionfrom 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 = 44100bank = cromafb(rate=rate)bank[0].plot(freq_scale="log", rate=rate)

Cromagrama

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 anliseG = 1e-2 # Ganho apenas para alinhamento na visualizao com a DFT

# Filtro de sntese(G / filt).plot(blk=data, rate=rate, samples=1024, unwrap=False).show()

Envoltria espectral
LPC - Predio Linear

Formantes

Pode ser utilizado para classificao de vogais

Parte 5
Interdisciplinaridade interna

Clculo numrico

Gerao de imagens

Fibonacci

h[0] = 0

h[1] = 1

h[n] = h[n-1] + h[n-2]Entrada [0, 1, 0, 0, 0, 0, ...] aplicado a esse filtro digital

Funo impulse()

In [2]: (z ** -1 / (1 - z ** -1 - z ** -2))(impulse(zero=0, ...: one=1), zero=0).take(17)Out[2]: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]

Polinmios

Baseados em dicionrioMemria

Expoente negativo (Laurent)

Expoente fracionrio (soma de potncias)

Objeto x

InterpolaoLagrange

In [9]: lagrange.poly([(0, 0), (1, 1)])Out[9]: x

In [10]: lagrange.poly([(0, 0), (1, 1), (2, 2)])Out[10]: x

In [11]: lagrange.poly([(0, 0), (1, 1), (2, 4)])Out[11]: x^2

In [9]: lagrange.poly([(1, 3), (3, 14), (45, 0)])Out[9]: -2.89773 + 6.0303 * x - 0.132576 * x^2

In [7]: (x + x ** 2 + x ** -.5)(4)Out[7]: 20.5

Licenas

LinguagemPython (CPython) PSFL

Processamento de SinaisAudioLazy (anlise, sntese e processamento) GPLv3

PyAudio (reproduo e gravao de udio) MIT

MatPlotLib (visualizao grfica) PSFL

NumPy (FFT, lgebra linear) BSD 3-Clause

SciPy (signal) BSD 3-Clause

GUIwxPython/wxWidgets wxWindows

[Tcl/]Tk BSD

Tkinter PSFL

Outrospy.test (testes automatizados) MIT

music21 (musicologia) LGPLv3+

Sphinx (documentao) BSD

Obrigado!

Perguntas?

Fork me on GitHubhttps://github.com/danilobellini/audiolazy

Foz do Iguau PR Processamento de sinais em Python2013-10-16 Danilo J. S. Bellini @danilobellini