Na Ć”rea de reconhecimento automĆ”tico de voz, uma das primeiras etapas estĆ” no processo de extração de caracterĆsticas dos sinais de voz, ou seja, identificar os componentes do sinal de Ć”udio que sĆ£o bons para identificar o conteĆŗdo linguĆstico. E uma dessas tĆ©cnicas de reconhecimento de voz estĆ” o Mel-Frequency Cepstral Coefficients (MFCCs), a qual foi introduzida na dĆ©cada de 1980 por Davis e Mermelstein e tem sido considerada o estado da arte atĆ© o momemento [1].
Os MFCCs são comumente obtidos através dos seguintes passos:
A operação do MFCC foi implementado para a tarefa 2 da disciplina de Fundamentos de Computação GrĆ”fica (FCG), a linguagem de programação escolhida foi o R. O código encontra-se disponĆvel no github.
devtools
contido no CRAN executando o seguinte comando no console do R: install.packages("devtools")
.install.packages('ggplot2')
).install.packages('tuneR')
).devtools::install_github("JessicaSousa/MFCC")
no console do R.Após efetuar a instalação do pacote, para usÔ-lo basta utilizar a seguinte função library(MFCC)
. Com o comando lsf("package:MFCC")
Ć© possĆvel obter uma lista contendo o nome das funƧƵes implementadas, conforme ilustrado abaixo:
#> [1] "%>%" "apply_dct"
#> [3] "apply_lifter" "apply_preemphasis"
#> [5] "apply_window_hamming" "calcule_filter_bank"
#> [7] "compute_mel_filterbanks" "compute_power_spectrum"
#> [9] "convert_hertz_to_mel" "convert_mel_to_hertz"
#> [11] "dct1" "dct2"
#> [13] "dct3" "dct4"
#> [15] "filter_bank_function" "frame_the_signal"
#> [17] "kronecker_delta" "mfcc_function"
#> [19] "nfft" "sound.data"
Para saber informações sobre alguma função, pode ser utilizado help('nome da função')
ou ?nome da função
.
Alguns exemplos do uso do pacote são ilustrados a seguir:
library(MFCC) #carregar pacote do MFCC
library(ggplot2) #biblioteca para grƔficos
#Obter arquivo de Ɣudio exemplo
sound.data <- MFCC::sound.data
#Com o pacote tuneR, pode-se carregar um arquivo do disco da seguinte forma: (descomentar abaixo)
#sound.data <- tuneR::readWave('audio.wav', from = 0, to = 3.5, units = "seconds")
sound <- sound.data@left #valores do arquivo de Ɣudio
sample.rate <- sound.data@samp.rate #sample rate do arquivo de Ɣudio
#Exibir arquivo de Ɣudio
sound.time <- 0:(length(sound)-1)/sample.rate #tempo em segundos
#criar estrutura contendo o x e y do grƔfico
data.raw <- data.frame(x = sound.time, y = sound)
#Exibir grƔfico
p <- ggplot(data.raw, aes(x, y)) + geom_line() +
xlab("Tempo (s)") + ylab("Amplitude") #+
Inicialmente, são definidos alguns parâmetros arbitrÔrios que são necessÔrios para o cÔlculo das MFCCs, são eles:
fft.npoints
), geralmente Ć© realizada uma FFT de 512 pontos.freq.lower
e freq.lower
, respectivamente)num.filters
), consiste em um conjunto de valores de 20-40.A seguir são inicializadas as respectivas variÔveis.
fft.npoints <- 512 #números de pontos considerados para o cÔlculo da fft
#help(nfft) #para mais informaƧƵes
freq.lower <- 0 #frequĆŖncia mĆnima em hertz considerada
freq.upper <- sample.rate / 2 #frequência mÔxima em hertz considerada
num.filters <- 40 #nĆŗmero filtros considerados para o filterbank
Antes de aplicar os passos da MFCCs, é aplicado um filtro de pré-ênfase sobre o sinal, com o objetivo de amplificar as altas frequências. A aplicação desse filtro pode ser obtida a partir da seguinte equação:
\[y(t) = x(t) - \alpha x(t-1)\]
Esse filtro foi implementado sobre o nome apply_preemphasis
, os valores padrões de \(\alpha\) são 0,95 ou 0,97. A seguir é ilustrado o resultado da aplicação do filtro sobre o sinal de som de entrada.
emphasized_signal <- apply_preemphasis(sound, 0.97)
#criar estrutura contendo o x e y do grƔfico
data.emphasized <- data.frame(x = sound.time, y = emphasized_signal)
#Exibição
p <- ggplot(data.emphasized, aes(x, y)) + geom_line() +
xlab("Tempo (s)") + ylab("Amplitude")
As etapas do algoritmo dos MFCCs são descritas juntamente com as chamadas de funções implementadas neste pacote:
frames <- frame_the_signal(emphasized_signal, sample.rate)#1.Dividir o sinal em short frames.
frames <- apply_window_hamming(frames) #aplicar a função de hamming para cada frame
power.frames <- compute_power_spectrum(frames, n = fft.npoints)
fbanks <- compute_mel_filterbanks(freq.lower,freq.upper, num.filters, fft.npoints, sample.rate)
#Para calcular a energia do filter bank, multiplica-se cada filter bank com seus power spectrum.
filter.banks <- power.frames %*% t(fbanks)
#substituir os zeros para evitar problemas com log
filter.banks[filter.banks == 0] <- .Machine$double.eps
filter.banks <- 20 * log10(filter.banks)
#Para cada FilterBank é aplicada a operação de Discrete Cosine Transform (DCT).
mfcc <- t(apply(filter.banks, 1, function(x) apply_dct(x)))
mfcc <- mfcc[, 2:13]
A visualização dos filterbanks pode ser vista com o seguinte trecho de código:
#Organizar dado para melhor visualização
x <- seq(from = freq.lower, to = freq.upper, length.out = ncol(fbanks)) %>% rep(num.filters)
y <- t(fbanks)
y %<>% as.data.frame() %>% tidyr::gather()
data <- data.frame(x = x, values = y$value, filters = y$key)
#Exibir espectograma
p <- ggplot(data, aes(x, values, colour = filters)) +
geom_line() + xlab("FrequĆŖncia") + ylab("Amplitude") + theme(legend.position="none") +
scale_x_continuous(expand = c(0, 0)) +
scale_y_continuous(expand = c(0, 0))
#Organizar dado para melhor visualização
fbanks.spec <- reshape2::melt(filter.banks)
fbanks.spec$Var1 <- fbanks.spec$Var1 / 100
fbanks.spec$Var2 <- fbanks.spec$Var2 / 10
#Exibir espectograma
p <- ggplot(fbanks.spec, aes(Var1,Var2)) + geom_raster(aes(fill = value)) +
scale_fill_gradientn(colours = rainbow(10)) +
xlab("Tempo (s)") + ylab("FrequĆŖncia (kHz)") + ggtitle("Espectograma do sinal") +
scale_x_continuous(expand = c(0, 0)) +
scale_y_continuous(expand = c(0, 0))
\[\hat{MFCC_i} = 1 + (\frac{w_i D}{2})\sin(\frac{Ļ n}{D})\]
E estÔ implementado sobre a seguinte função apply_lifter
:
#Aplicar o sinusoidal liftering aos MFCCs
mfcc.lift <- apply_lifter(mfcc)
#Organizar dado para melhor visualização
mfccs.spec <- reshape2::melt(mfcc.lift)
mfccs.spec$Var1 <- mfccs.spec$Var1 / 100
#Espectograma do MFCCs
p <- ggplot(mfccs.spec, aes(Var1,Var2, fill=value)) + geom_raster(aes(fill = value)) +
scale_fill_gradientn(colours = rainbow(10)) +
xlab("Tempo (s)") + ylab("Coeficientes das MFCCs") + ggtitle("MFCCs") +
scale_x_continuous(expand = c(0, 0)) +
scale_y_continuous(expand = c(0, 0))