Commit 254954ae authored by André Anjos's avatar André Anjos 💬

Move AP library into the package

parent 8c62a1b1
/**
* @date Wed Jan 11:09:30 2013 +0200
* @author Elie Khoury <Elie.Khoury@idiap.ch>
* @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
*
* @brief Implement Linear and Mel Frequency Cepstral Coefficients
* functions (MFCC and LFCC)
*
* Copyright (C) Idiap Research Institute, Martigny, Switzerland
*/
#include "Ceps.h"
#include <bob/core/assert.h>
bob::ap::Ceps::Ceps(const double sampling_frequency,
const double win_length_ms, const double win_shift_ms,
const size_t n_filters, const size_t n_ceps, const double f_min,
const double f_max, const size_t delta_win, const double pre_emphasis_coeff,
const bool mel_scale, const bool dct_norm):
bob::ap::Spectrogram(sampling_frequency, win_length_ms, win_shift_ms,
n_filters, f_min, f_max, pre_emphasis_coeff, mel_scale),
m_n_ceps(n_ceps), m_delta_win(delta_win), m_dct_norm(dct_norm),
m_with_energy(false), m_with_delta(false), m_with_delta_delta(false)
{
setEnergyBands(true);
initCacheDctKernel();
}
bob::ap::Ceps::Ceps(const bob::ap::Ceps& other):
bob::ap::Spectrogram(other),
m_n_ceps(other.m_n_ceps), m_delta_win(other.m_delta_win),
m_dct_norm(other.m_dct_norm), m_with_energy(other.m_with_energy),
m_with_delta(other.m_with_delta),
m_with_delta_delta(other.m_with_delta_delta)
{
initCacheDctKernel();
}
bob::ap::Ceps&
bob::ap::Ceps::operator=(const bob::ap::Ceps& other)
{
if (this != &other)
{
bob::ap::Spectrogram::operator=(other);
m_n_ceps = other.m_n_ceps;
m_delta_win = other.m_delta_win;
m_dct_norm = other.m_dct_norm;
m_with_energy = other.m_with_energy;
m_with_delta = other.m_with_delta;
m_with_delta_delta = other.m_with_delta_delta;
initCacheDctKernel();
}
return *this;
}
bool bob::ap::Ceps::operator==(const bob::ap::Ceps& other) const
{
return (bob::ap::Spectrogram::operator==(other) &&
m_n_ceps == other.m_n_ceps &&
m_delta_win == other.m_delta_win &&
m_dct_norm == other.m_dct_norm &&
m_with_energy == other.m_with_energy &&
m_with_delta == other.m_with_delta &&
m_with_delta_delta == other.m_with_delta_delta);
}
bool bob::ap::Ceps::operator!=(const bob::ap::Ceps& other) const
{
return !(this->operator==(other));
}
bob::ap::Ceps::~Ceps()
{
}
void bob::ap::Ceps::setNFilters(size_t n_filters)
{
bob::ap::Spectrogram::setNFilters(n_filters);
initCacheDctKernel();
}
void bob::ap::Ceps::setNCeps(size_t n_ceps)
{
m_n_ceps = n_ceps;
initCacheFilterBank();
initCacheDctKernel();
}
void bob::ap::Ceps::setDctNorm(bool dct_norm)
{
m_dct_norm = dct_norm;
initCacheDctKernel();
}
void bob::ap::Ceps::initCacheDctKernel()
{
// Dct Kernel initialization
m_dct_kernel.resize(m_n_ceps,m_n_filters);
blitz::firstIndex i;
blitz::secondIndex j;
double dct_coeff = m_dct_norm ? (double)sqrt(2./(double)(m_n_filters)) : 1.;
m_dct_kernel = dct_coeff * blitz::cos(M_PI*(i+1)*(j+0.5)/(double)(m_n_filters));
}
blitz::TinyVector<int,2> bob::ap::Ceps::getShape(const size_t input_size) const
{
// Res will contain the number of frames x the dimension of the feature vector
blitz::TinyVector<int,2> res;
// 1. Number of frames
res(0) = 1+((input_size-m_win_length)/m_win_shift);
// 2. Dimension of the feature vector
int dim0=m_n_ceps;
if (m_with_energy) dim0 += 1;
int dim = dim0;
if (m_with_delta)
{
dim += dim0;
if(m_with_delta_delta) dim += dim0;
}
res(1) = dim;
return res;
}
blitz::TinyVector<int,2> bob::ap::Ceps::getShape(const blitz::Array<double,1>& input) const
{
return getShape(input.extent(0));
}
void bob::ap::Ceps::operator()(const blitz::Array<double,1>& input,
blitz::Array<double,2>& ceps_matrix)
{
// Get expected dimensionality of output array
blitz::TinyVector<int,2> feature_shape = bob::ap::Ceps::getShape(input);
// Check dimensionality of output array
bob::core::array::assertSameShape(ceps_matrix, feature_shape);
int n_frames=feature_shape(0);
blitz::Range r1(0,m_n_ceps-1);
for (int i=0; i<n_frames; ++i)
{
// Set padded frame to zero
extractNormalizeFrame(input, i, m_cache_frame_d);
// Update output with energy if required
if (m_with_energy)
ceps_matrix(i,(int)m_n_ceps) = logEnergy(m_cache_frame_d);
// Apply pre-emphasis
pre_emphasis(m_cache_frame_d);
// Apply the Hamming window
hammingWindow(m_cache_frame_d);
// Take the power spectrum of the first part of the FFT
powerSpectrumFFT(m_cache_frame_d);
// Filter with the triangular filter bank (either in linear or Mel domain)
filterBank(m_cache_frame_d);
// Apply DCT kernel and update the output
blitz::Array<double,1> ceps_matrix_row(ceps_matrix(i,r1));
applyDct(ceps_matrix_row);
}
//compute the center of the cut-off frequencies
const int n_coefs = (m_with_energy ? m_n_ceps + 1 : m_n_ceps);
blitz::Range rall = blitz::Range::all();
blitz::Range ro0(0,n_coefs-1);
blitz::Range ro1(n_coefs,2*n_coefs-1);
blitz::Range ro2(2*n_coefs,3*n_coefs-1);
if (m_with_delta)
{
blitz::Array<double,2> ceps_matrix_0(ceps_matrix(rall,ro0));
blitz::Array<double,2> ceps_matrix_1(ceps_matrix(rall,ro1));
addDerivative(ceps_matrix_0, ceps_matrix_1);
if (m_with_delta_delta)
{
blitz::Array<double,2> ceps_matrix_2(ceps_matrix(rall,ro2));
addDerivative(ceps_matrix_1, ceps_matrix_2);
}
}
}
void bob::ap::Ceps::applyDct(blitz::Array<double,1>& ceps_row) const
{
blitz::firstIndex i;
blitz::secondIndex j;
ceps_row = blitz::sum(m_cache_filters(j) * m_dct_kernel(i,j), j);
}
void bob::ap::Ceps::addDerivative(const blitz::Array<double,2>& input, blitz::Array<double,2>& output) const
{
// Initialize output to zero
output = 0.;
const int n_frames = input.extent(0);
blitz::Range rall = blitz::Range::all();
// Fill in the inner part as follows:
// \f$output[i] += \sum_{l=1}^{DW} l * (input[i+l] - input[i-l])\f$
for (int l=1; l<=(int)m_delta_win; ++l) {
blitz::Range rout(l,n_frames-l-1);
blitz::Range rp(2*l,n_frames-1);
blitz::Range rn(0,n_frames-2*l-1);
output(rout,rall) += l*(input(rp,rall) - input(rn,rall));
}
const double factor = m_delta_win*(m_delta_win+1)/2;
// Continue to fill the left boundary part as follows:
// \f$output[i] += (\sum_{l=1+i}^{DW} l*input[i+l]) - (\sum_{l=i+1}^{DW}l)*input[0])\f$
for (int i=0; i<(int)m_delta_win; ++i) {
output(i,rall) -= (factor - i*(i+1)/2) * input(0,rall);
for (int l=1+i; l<=(int)m_delta_win; ++l) {
output(i,rall) += l*(input(i+l,rall));
}
}
// Continue to fill the right boundary part as follows:
// \f$output[i] += (\sum_{l=Nframes-1-i}^{DW}l)*input[Nframes-1]) - (\sum_{l=Nframes-1-i}^{DW} l*input[i-l])\f$
for (int i=n_frames-(int)m_delta_win; i<n_frames; ++i) {
int ii = (n_frames-1)-i;
output(i,rall) += (factor - ii*(ii+1)/2) * input(n_frames-1,rall);
for (int l=1+ii; l<=(int)m_delta_win; ++l) {
output(i,rall) -= l*input(i-l,rall);
}
}
// Sum of the integer squared from 1 to delta_win
const double sum = m_delta_win*(m_delta_win+1)*(2*m_delta_win+1)/3;
output /= sum;
}
/*
bob::ap::TestCeps::TestCeps(Ceps& ceps): m_ceps(ceps) {
}
*/
/**
* @author Elie Khoury <Elie.Khoury@idiap.ch>
* @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
* @date Wed Jan 11:10:20 2013 +0200
*
* @brief Implement Linear and Mel Frequency Cepstral Coefficients
* functions (MFCC and LFCC)
*
* Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
*/
#ifndef BOB_AP_CEPS_H
#define BOB_AP_CEPS_H
#include <blitz/array.h>
#include "Spectrogram.h"
namespace bob {
/**
* \ingroup libap_api
* @{
*
*/
namespace ap {
/**
* @brief This class is used to test the Ceps class (private methods)
*/
//class CepsTest;
/**
* @brief This class allows the extraction of features from raw audio data.
* References:
* 1. SPro tools (http://www.irisa.fr/metiss/guig/spro/spro-4.0.1/spro.html)
* 2. Wikipedia (http://en.wikipedia.org/wiki/Mel-frequency_cepstrum).
*/
class Ceps: public Spectrogram
{
public:
/**
* @brief Constructor. Initializes working arrays
*/
Ceps(const double sampling_frequency, const double win_length_ms=20.,
const double win_shift_ms=10., const size_t n_filters=24,
const size_t n_ceps=19, const double f_min=0.,
const double f_max=4000., const size_t delta_win=2,
const double pre_emphasis_coef=0.95, const bool mel_scale=true,
const bool dct_norm=false);
/**
* @brief Copy constructor.
*/
Ceps(const Ceps& other);
/**
* @brief Assignment operator
*/
Ceps& operator=(const Ceps& other);
/**
* @brief Equal to
*/
bool operator==(const Ceps& other) const;
/**
* @brief Not equal to
*/
bool operator!=(const Ceps& other) const;
/**
* @brief Destructor
*/
virtual ~Ceps();
/**
* @brief Gets the Cepstral features shape for a given input/input length
*/
blitz::TinyVector<int,2> getShape(const size_t input_length) const;
blitz::TinyVector<int,2> getShape(const blitz::Array<double,1>& input) const;
/**
* @brief Computes Cepstral features
*/
void operator()(const blitz::Array<double,1>& input, blitz::Array<double,2>& output);
/**
* @brief Returns the sampling frequency/frequency rate
*/
double getSamplingFrequency() const
{ return m_sampling_frequency; }
/**
* @brief Returns the number of cepstral coefficient to keep
*/
size_t getNCeps() const
{ return m_n_ceps; }
/**
* @brief Rerturns the size of the window used to compute first and second
* order derivatives
*/
size_t getDeltaWin() const
{ return m_delta_win; }
/**
* @brief Tells whether the DCT coefficients are normalized or not
*/
bool getDctNorm() const
{ return m_dct_norm; }
/**
* @brief Tells whether the energy is added to the cepstral coefficients
* or not
*/
bool getWithEnergy() const
{ return m_with_energy; }
/**
* @brief Tells whether the first order derivatives are added to the
* cepstral coefficients or not
*/
bool getWithDelta() const
{ return m_with_delta; }
/**
* @brief Tells whether the second order derivatives are added to the
* cepstral coefficients or not
*/
bool getWithDeltaDelta() const
{ return m_with_delta_delta; }
/**
* @brief Returns the number of filters to keep
*/
virtual void setNFilters(size_t n_ceps);
/**
* @brief Returns the number of cepstral coefficient to keep
*/
virtual void setNCeps(size_t n_ceps);
/**
* @brief Sets the size of the window used to compute first and second
* order derivatives
*/
virtual void setDeltaWin(size_t delta_win)
{ m_delta_win = delta_win; }
/**
* @brief Sets whether the DCT coefficients are normalized or not
*/
virtual void setDctNorm(bool dct_norm);
/**
* @brief Sets whether the energy is added to the cepstral coefficients
* or not
*/
void setWithEnergy(bool with_energy)
{ m_with_energy = with_energy; }
/**
* @brief Sets whether the first order derivatives are added to the
* cepstral coefficients or not
*/
void setWithDelta(bool with_delta)
{ if (!with_delta) m_with_delta_delta = false;
m_with_delta = with_delta; }
/**
* @brief Sets whether the first order derivatives are added to the
* cepstral coefficients or not. If enabled, first order derivatives are
* automatically enabled as well.
*/
void setWithDeltaDelta(bool with_delta_delta)
{ if (with_delta_delta) m_with_delta = true;
m_with_delta_delta = with_delta_delta; }
private:
/**
* @brief Computes the first order derivative from the given input.
* This methods is used to compute both the delta's and double delta's.
*/
void addDerivative(const blitz::Array<double,2>& input, blitz::Array<double,2>& output) const;
/**
* @brief Applies the DCT to the cepstral features:
* \f$out[i]=sqrt(2/N)*sum_{j=1}^{N} (in[j]cos(M_PI*i*(j-0.5)/N)\f$
*/
void applyDct(blitz::Array<double,1>& ceps_row) const;
void initCacheDctKernel();
/**
* @brief Initialize the table m_p_index, which contains the indices of
* the cut-off frequencies of the triangular filters.. It looks like:
*
* filter 2
* <------------->
* filter 1 filter 4
* <-----------> <------------->
* | | | | | | | | | | | | | | | | | | | | | ..........
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 ..........
* ^ ^ ^ ^ ^
* | | | | |
* t[0] | t[2] | t[4]
* t[1] t[3]
*
*/
void initCachePIndex();
void initCacheFilters();
size_t m_n_ceps;
size_t m_delta_win;
bool m_dct_norm;
bool m_with_energy;
bool m_with_delta;
bool m_with_delta_delta;
blitz::Array<double,2> m_dct_kernel;
// friend class TestCeps;
};
}}
#endif /* BOB_AP_CEPS_H */
/**
* @date Wed Jan 11:09:30 2013 +0200
* @author Elie Khoury <Elie.Khoury@idiap.ch>
* @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
*
* Copyright (C) Idiap Research Institute, Martigny, Switzerland
*/
#include "Energy.h"
#include <bob/core/assert.h>
bob::ap::Energy::Energy(const double sampling_frequency, const double win_length_ms,
const double win_shift_ms):
bob::ap::FrameExtractor(sampling_frequency, win_length_ms, win_shift_ms),
m_energy_floor(1.)
{
// Initializes logarithm of flooring values
m_log_energy_floor = log(m_energy_floor);
}
bob::ap::Energy::Energy(const bob::ap::Energy& other):
bob::ap::FrameExtractor(other), m_energy_floor(1.)
{
// Initializes logarithm of flooring values
m_log_energy_floor = log(m_energy_floor);
}
bob::ap::Energy& bob::ap::Energy::operator=(const bob::ap::Energy& other)
{
if (this != &other)
{
bob::ap::FrameExtractor::operator=(other);
m_energy_floor = other.m_energy_floor;
// Initializes logarithm of flooring values
m_log_energy_floor = log(m_energy_floor);
}
return *this;
}
bool bob::ap::Energy::operator==(const bob::ap::Energy& other) const
{
return (bob::ap::FrameExtractor::operator==(other) &&
m_energy_floor == other.m_energy_floor);
}
bool bob::ap::Energy::operator!=(const bob::ap::Energy& other) const
{
return !(bob::ap::Energy::operator==(other));
}
bob::ap::Energy::~Energy()
{
}
blitz::TinyVector<int,2>
bob::ap::Energy::getShape(const size_t input_size) const
{
blitz::TinyVector<int,2> res = bob::ap::FrameExtractor::getShape(input_size);
res(1) = 1;
return res;
}
blitz::TinyVector<int,2>
bob::ap::Energy::getShape(const blitz::Array<double,1>& input) const
{
return getShape(input.extent(0));
}
void bob::ap::Energy::operator()(const blitz::Array<double,1>& input,
blitz::Array<double,1>& energy_array)
{
// Get expected dimensionality of output array
int n_frames = bob::ap::Energy::getShape(input)(0);
// Check dimensionality of output array
bob::core::array::assertSameDimensionLength(energy_array.extent(0), n_frames);
for (int i=0; i<n_frames; ++i)
{
// Extract and normalize frame
extractNormalizeFrame(input, i, m_cache_frame_d);
// Update output with logEnergy
energy_array(i) = logEnergy(m_cache_frame_d);
}
}
double bob::ap::Energy::logEnergy(blitz::Array<double,1> &data) const
{
blitz::Array<double,1> data_p(data(blitz::Range(0,(int)m_win_length-1)));
double gain = blitz::sum(blitz::pow2(data_p));
return (gain < m_energy_floor ? m_log_energy_floor : log(gain));
}
/**
* @author Elie Khoury <Elie.Khoury@idiap.ch>
* @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
* @date Wed Jan 11:10:20 2013 +0200
*
* Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
*/
#ifndef BOB_AP_ENERGY_H
#define BOB_AP_ENERGY_H
#include <blitz/array.h>
#include "FrameExtractor.h"
namespace bob {
/**
* \ingroup libap_api
* @{
*
*/
namespace ap {
/**
* @brief This class allows the extraction of energy in a frame basis
*/
class Energy: public FrameExtractor
{
public:
/**
* @brief Constructor. Initializes working arrays
*/
Energy(const double sampling_frequency, const double win_length_ms=20.,
const double win_shift_ms=10.);
/**
* @brief Copy constructor
*/
Energy(const Energy& other);
/**
* @brief Assignment operator
*/
Energy& operator=(const Energy& other);
/**
* @brief Equal to
*/
bool operator==(const Energy& other) const;
/**
* @brief Not equal to
*/
bool operator!=(const Energy& other) const;
/**
* @brief Destructor
*/
virtual ~Energy();
/**
* @brief Gets the Energy features shape for a given input/input length
*/
virtual blitz::TinyVector<int,2> getShape(const size_t input_length) const;
virtual blitz::TinyVector<int,2> getShape(const blitz::Array<double,1>& input) const;
/**
* @brief Computes Energy features
*/
void operator()(const blitz::Array<double,1>& input, blitz::Array<double,1>& output);
/**
* @brief Gets the energy floor
*/
virtual double getEnergyFloor() const
{ return m_energy_floor; }
/**
* @brief Sets the energy floor
*/
virtual void setEnergyFloor(double energy_floor)
{ m_energy_floor = energy_floor;
m_log_energy_floor = log(m_energy_floor); }
protected:
/**
* @brief Computes the logarithm of the energy
*/
double logEnergy(blitz::Array<double,1> &data) const;
double m_energy_floor;
double m_log_energy_floor;
};
}}
#endif /* BOB_AP_ENERGY_H */
/**
* @date Wed Jan 11:09:30 2013 +0200
* @author Elie Khoury <Elie.Khoury@idiap.ch>
* @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
*
* Copyright (C) Idiap Research Institute, Martigny, Switzerland
*/
#include <stdexcept>
#include "FrameExtractor.h"
#include <bob/core/check.h>
bob::ap::FrameExtractor::FrameExtractor(const double sampling_frequency,
const double win_length_ms, const double win_shift_ms):
m_sampling_frequency(sampling_frequency), m_win_length_ms(win_length_ms),
m_win_shift_ms(win_shift_ms)
{
// Initialization
initWinLength();
initWinShift();
}
bob::ap::FrameExtractor::FrameExtractor(const FrameExtractor& other):
m_sampling_frequency(other.m_sampling_frequency),
m_win_length_ms(other.m_win_length_ms),
m_win_shift_ms(other.m_win_shift_ms)
{
// Initialization
initWinLength();
initWinShift();
}
bob::ap::FrameExtractor::~FrameExtractor()
{
}
bob::ap::FrameExtractor& bob::ap::FrameExtractor::operator=(const bob::ap::FrameExtractor& other)
{
if (this != &other)
{
m_sampling_frequency = other.m_sampling_frequency;
m_win_length_ms = other.m_win_length_ms;
m_win_shift_ms = other.m_win_shift_ms;
// Initialization
initWinLength();
initWinShift();
}
return *this;
}
bool bob::ap::FrameExtractor::operator==(const bob::ap::FrameExtractor& other) const
{
return (m_sampling_frequency == other.m_sampling_frequency &&
m_win_length_ms == other.m_win_length_ms &&
m_win_shift_ms == other.m_win_shift_ms);
}
bool bob::ap::FrameExtractor::operator!=(const bob::ap::FrameExtractor& other) const
{
return !(this->operator==(other));
}
void bob::ap::FrameExtractor::setSamplingFrequency(const double sampling_frequency)
{
m_sampling_frequency = sampling_frequency;
initWinLength();
initWinShift();
}
void bob::ap::FrameExtractor::setWinLengthMs(const double win_length_ms)
{
m_win_length_ms = win_length_ms;
initWinLength();
}
void bob::ap::FrameExtractor::setWinShiftMs(const double win_shift_ms)
{
m_win_shift_ms = win_shift_ms;