Ao fim desta unidade, o aluno será capaz de utilizar estatísticas de descritores de timbre como um indicador do conteúdo de um arquivo de áudio
Antes de iniciar esta unidade, o aluno deve sentir-se confortável com a seguinte afirmação:
É possível calcular características objetivas de um espectrograma de forma a caracterizar aspectos de seu conteúdo acústico.
Um vetor é um conjunto ordenado de medidas escalares. Por exemplo, podemos indicar um ponto na superfície terrestre através de um par ordenado $(a, b)$, onde $a$ é a longitude e $b$ é a latitude de um ponto. O mesmo vale para o plano Euclidiano: nele, qualquer ponto pode ser definido por um par $(x, y)$.
Um vetor é, usualmente, denotado por uma letra minúscula em negrito, tal qual $\boldsymbol x$. O $n$-ésmio elemento de um vetor é denotado $x_n$ (sem negrito). Para vetores, valem as seguintes propriedades:
A soma de dois vetores é um vetor composto pela soma de seus elementos correspondentes. Assim, se $\boldsymbol z = \boldsymbol y + \boldsymbol x$, então $z_n = y_n + x_n$.
A multiplicação de um vetor por um número escalar resulta num vetor no qual cada um dos elementos do vetor original foi multiplicado por esse número escalar. Assim, se $\boldsymbol y = a \boldsymbol x$, então $y_n = a x_n$.
O módulo de um vetor é igual ao comprimento da reta que o liga à origem. Para vetores de dimensão arbitrária $N$, a norma $||\boldsymbol x ||$ é dada por: $$|| \boldsymbol x || = \sqrt{\sum_{n=1}^N x_n^2}.$$
A distância Euclidiana entre dois vetores é igual ao módulo de sua diferença, isto é: $$d(\boldsymbol x, \boldsymbol y) = || \boldsymbol y - \boldsymbol x || = || \boldsymbol x - \boldsymbol y || = \sqrt{\sum_{n=1}^N (x_n-y_n)^2}.$$
In [1]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
# Demonstrando propriedades de vetores
# Ideia: coloque mais dimensoes nos vetores e veja o que acontece!
x = np.array([4, 3])
y = np.array([3, 4])
print x
print y
print x + y # Soma de vetores
print 10 * x # Multiplicacao por escalar
print np.linalg.norm(y), np.linalg.norm(x) # Modulo de vetores
print np.linalg.norm(y-x), np.linalg.norm(x-y) # Distancia euclidiana
Podemos utilizar vetores para registrar uma série de medições de um mesmo fenômeno. Um sinal digitalizado, por exemplo, pode ser considerado um vetor. Assim, é possível tomar um certo conjunto de amostras de dois sinais e calcular sua distância Euclidiana, por exemplo. Na notação que aplicamos para sinais, teríamos: $$d(\boldsymbol x, \boldsymbol y) = \sqrt{\sum_{n=0}^{N-1} (x[n]-y[n])^2}.$$
Assim, verificamos que vetores e sinais podem ser representados da mesma maneira, e, portanto, podemos aplicar propriedades de sinais em vetores e propriedades de vetores em sinais.
Em vetores, tanto quanto em sinais ou em um conjunto qualquer de números, podemos calcular medidas estatísticas. Elas descrevem como um sinal se comporta ao longo de várias medições, sob um ponto de vista estatístico.
A média de um conjunto de amostras é dada por: $$\mu_x = \frac{\sum_{n=0}^{N-1} x[n]}{N}.$$
A média é o valor $a$ que minimiza a soma dos quadrados das distâncias $(a-x[n])^2$ ao longo de todas as amostras, isto é: $$\mu_x = \arg \min_a \sum_{n=0}^{N-1} (a-x[n])^2.$$
Ainda assim, sempre que houver qualquer tipo de variação em um sinal $x[n]$, é impossível escolher um valor que leva a soma de todas as distâncias a zero. A medida que indica qual é a dispersão residual é a variância, dada por: $$\sigma^2_x = \sum_{n=0} ^{N-1} (\mu_x - x[n])^2.$$
A media $\sigma_x = \sqrt{\sigma_x^2}$ é chamada de desvio padrão.
In [2]:
# Demonstrando propriedades de vetores
# Ideia: coloque mais dimensoes nos vetores e veja o que acontece!
x = np.array([-40, -30, 30, 40])
y = np.array([3, 4, -3, -4])
z = np.array([0, 1, -6, -7])
print np.mean(x), np.mean(y), np.mean(z) # Medias
print np.var(x), np.var(y), np.var(z) # Variancias
Uma operação matemática interessante que podemos fazer é a de normalizar vetores. Esta operação resulta em um vetor com média zero e variância unitária. O vetor $\boldsymbol x_{\mbox{normalizado}}$ pode ser calculado por: $$\boldsymbol x_{\mbox{normalizado}} = \frac{\boldsymbol x-\mu_x}{\sigma_x}.$$
In [3]:
x = np.array([4, 3, 2, 4, 3.2, 1, 2, 90, 1, 2, 3, 4])
x_norm = (x - np.mean(x))/np.sqrt(np.var(x))
print np.mean(x), np.mean(x_norm)
print np.var(x), np.var(x_norm)
Nesta análise, vamos verificar como as estatísticas de descritores de áudio podem ser utilizadas para identificar, de forma objetiva, o conteúdo de descritores.
No código que segue, calcularemos o flatness espectral ao longo de quadros de curta duração de três trechos de áudio, contendo, respectivamente uma percussão, uma guitarra e um coral. Após, mostraremos os valores calculados em um histograma.
In [4]:
import mir3.modules.tool.wav2spectrogram as spectrogram
import mir3.modules.features.flatness as flatness
fnames = ['audio/tabla.wav', 'audio/bbking.wav', 'audio/chorus.wav']
flat_samples = []
for fname in fnames:
wav2spec = spectrogram.Wav2Spectrogram() # Objeto que converte arquivos wav para espectrogramas
s = wav2spec.convert(open(fname, 'rb'), window_length=1024, window_step=512, spectrum_type='magnitude')
fness = flatness.Flatness()
f = fness.calc_track(s)
flat_samples.append(f.data)
plt.figure();
plt.hist(flat_samples, 15, normed=1, histtype='bar',
color=['red', 'blue', 'green'],
label=['Tabla', 'Guitarra', 'Coral']);
plt.xlabel('Flatness');
plt.ylabel('Quantidade de quadros');
plt.legend(loc=1);
Podemos, neste momento, detectar alguns comportamentos interessantes:
Veja que essas observações indicam que a média (a tendência geral) e a variância (dispersão) podem ser boas formas de descrever esses histogramas em uma forma mais compacta
In [5]:
m = []
s =[]
for a in xrange(3):
m.append(np.mean(flat_samples[a]))
s.append(np.var(flat_samples[a]))
print fnames[a], np.mean(flat_samples[a]), np.var(flat_samples[a])
É importante perceber que este procedimento permite relacionar arquivos de áudio a um vetor, de tantas dimensões quanto se queira (poderíamos expandir este procedimento para incluir outros descritores, por exemplo).
Esses vetores podem ser mostrados numa figura:
In [6]:
color=['red', 'blue', 'green']
label=['Tabla', 'Guitarra', 'Coral']
plt.figure();
for a in xrange(len(m)):
plt.scatter(m[a], s[a], color=color[a], label=label[a])
plt.xlabel('Media de flatness')
plt.ylabel('Variancia de flatness')
plt.legend(label, loc=4);
plt.show()
Até o momento, mostramos como relacionar arquivos de áudio a vetores, mas não há nenhuma prova de que esses vetores são representativos quanto ao conteúdo acústico que utilizamos como base. Vamos começar esse processo de forma anedotal, utilizando o arquivo de áudio que foi usado como exercício na unidade anterior. Calcularemos a média e a variância de seu flatness espectral ao longo do tempo, e então mostraremos como o vetor resultante se relaciona com os anteriores.
In [7]:
wav2spec = spectrogram.Wav2Spectrogram() # Objeto que converte arquivos wav para espectrogramas
spec = wav2spec.convert(open('audio/testing.wav', 'rb'), window_length=1024, window_step=512, spectrum_type='magnitude')
fness = flatness.Flatness()
f = fness.calc_track(spec)
m.append(np.mean(f.data))
s.append(np.var(f.data))
color=['red', 'blue', 'green', 'black']
label=['Tabla', 'Guitarra', 'Coral', 'Teste']
plt.figure();
for a in xrange(len(m)):
plt.scatter(m[a], s[a], color=color[a], label=label[a])
plt.xlabel('Media de flatness')
plt.ylabel('Variancia de flatness')
plt.legend(label, loc=4);
plt.show()
Podemos visualizar que o ponto de teste parece mais próximo do vetor da Tabla que dos demais. Podemos calcular essa distância:
In [8]:
for i in xrange(3):
print label[i], np.linalg.norm( np.array([s[-1]-s[i], m[-1]-m[i]]))
Portanto, o ponto está mais próximo de nossa referência para o som de tabla que dos demais.
Modifique o código computacional fornecido de forma a utilizar outros descritores, já vistos em aula.
(começar em sala, continuar em casa) Encontre por volta de 20 arquivos de áudio que podem ser agrupados em duas categorias diferentes, à sua escolha (sugestão: use o FreeSound). Mostre, através de histogramas, como as duas categorias podem ser diferenciadas por meio de descritores calculados automaticamente. Na aula seguinte, apresente seus resultados para a classe.
In [ ]: