rename + missing

This commit is contained in:
Dave Griffiths 2015-07-09 21:50:03 +01:00
parent d2b56e53e2
commit cb1ca8e0e3
6 changed files with 433 additions and 0 deletions

138
samplebrain/src/block.cpp Normal file
View File

@ -0,0 +1,138 @@
#include <assert.h>
#include <iostream>
#include "libmfcc.h"
#include "block.h"
using namespace spiralcore;
FFT *block::m_fftw;
Aquila::Mfcc *block::m_mfcc_proc;
static const int MFCC_FILTERS=12;
void enveloper(sample &s, u32 start, u32 end) {
for(u32 i=0; i<start; ++i) {
s[i]*=i/(float)start;
}
for(u32 i=0; i<end; ++i) {
s[(s.get_length()-1)-i]*=i/(float)end;
}
}
block::block(const string &filename, const sample &pcm, u32 rate, bool ditchpcm) :
m_pcm(pcm),
m_fft(pcm.get_length()),
m_mfcc(MFCC_FILTERS),
m_block_size(pcm.get_length()),
m_rate(rate),
m_orig_filename(filename)
{
init_fft(m_pcm.get_length());
assert(m_mfcc_proc!=NULL);
assert(m_fftw!=NULL);
enveloper(m_pcm,50,50);
m_fftw->impulse2freq(m_pcm.get_non_const_buffer());
std::vector<std::complex<double>> mfspec;
for (u32 i=0; i<m_block_size; ++i) {
m_fft[i]=m_fftw->m_spectrum[i][0];
mfspec.push_back(std::complex<double>(m_fftw->m_spectrum[i][0],
m_fftw->m_spectrum[i][1]));
}
if (m_block_size>100) m_fft.crop_to(100);
if (ditchpcm) m_pcm.clear();
// calculate mfcc
std::vector<double> m = m_mfcc_proc->calculate(mfspec,MFCC_FILTERS);
for (u32 i=0; i<MFCC_FILTERS; ++i) {
m_mfcc[i] = m[i];
}
}
void block::init_fft(u32 block_size)
{
if (m_fftw == NULL || m_fftw->m_length!=block_size) {
if (m_fftw == NULL) delete m_fftw;
m_fftw = new FFT(block_size);
if (m_mfcc_proc == NULL) delete m_mfcc_proc;
m_mfcc_proc = new Aquila::Mfcc(block_size);
}
}
double block::compare(const block &other, float ratio) const {
double mfcc_acc=0;
double fft_acc=0;
if (ratio==0) {
for (u32 i=0; i<m_fft.get_length(); ++i) {
fft_acc+=(m_fft[i]-other.m_fft[i]) * (m_fft[i]-other.m_fft[i]);
}
return fft_acc/(float)m_fft.get_length();
}
if (ratio==1) {
for (u32 i=0; i<MFCC_FILTERS; ++i) {
mfcc_acc+=(m_mfcc[i]-other.m_mfcc[i]) * (m_mfcc[i]-other.m_mfcc[i]);
}
return mfcc_acc/(float)MFCC_FILTERS;
}
// calculate both
for (u32 i=0; i<m_fft.get_length(); ++i) {
fft_acc+=(m_fft[i]-other.m_fft[i]) * (m_fft[i]-other.m_fft[i]);
}
for (u32 i=0; i<MFCC_FILTERS; ++i) {
mfcc_acc+=(m_mfcc[i]-other.m_mfcc[i]) * (m_mfcc[i]-other.m_mfcc[i]);
}
return (fft_acc/(float)m_fft.get_length())*(1-ratio) +
(mfcc_acc/(float)MFCC_FILTERS)*ratio;
}
bool block::unit_test() {
sample data(200);
for (u32 i=0; i<data.get_length(); i++) {
data[i]=i/(float)data.get_length();
}
block bb("test",data,44100);
assert(bb.m_pcm.get_length()==data.get_length());
//assert(bb.m_fft.get_length()==data.get_length());
assert(bb.m_mfcc.get_length()==MFCC_FILTERS);
assert(bb.m_orig_filename==string("test"));
assert(bb.m_rate==44100);
assert(bb.m_block_size==data.get_length());
block bb2("test",data,44100);
assert(bb.compare(bb2,1)==0);
assert(bb.compare(bb2,0)==0);
assert(bb.compare(bb2,0.5)==0);
sample data2(200);
for (u32 i=0; i<data.get_length(); i++) {
data[i]=i%10;
}
block cpy("test",data,100);
{
block bb3("test",data2,44100);
assert(bb.compare(bb3,1)!=0);
assert(bb.compare(bb3,0)!=0);
assert(bb.compare(bb3,0.5)!=0);
cpy=bb3;
}
assert(cpy.m_pcm.get_length()==200);
return true;
}

40
samplebrain/src/block.h Normal file
View File

@ -0,0 +1,40 @@
#include <string>
#include "jellyfish/fluxa/sample.h"
#include "jellyfish/core/types.h"
#include "fft.h"
#include "mfcc.h"
#ifndef BLOCK
#define BLOCK
namespace spiralcore {
class block {
public:
// runs analysis on pcm
block(const std::string &filename, const sample &pcm, u32 rate, bool ditchpcm=false);
// returns distance based on ratio of fft-mfcc values
double compare(const block &other, float ratio) const;
static void init_fft(u32 block_size);
static bool unit_test();
const sample &get_pcm() const { return m_pcm; }
private:
sample m_pcm;
sample m_fft;
sample m_mfcc;
u32 m_block_size;
u32 m_rate;
std::string m_orig_filename;
static FFT *m_fftw;
static Aquila::Mfcc *m_mfcc_proc;
};
}
#endif

35
samplebrain/src/mfcc.cpp Normal file
View File

@ -0,0 +1,35 @@
/**
* @file Mfcc.cpp
*
* Calculation of MFCC signal features.
*
* This file is part of the Aquila DSP library.
* Aquila is free software, licensed under the MIT/X11 License. A copy of
* the license is provided with the library in the LICENSE file.
*
* @package Aquila
* @version 3.0.0-dev
* @author Zbigniew Siciarz
* @date 2007-2014
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @since 3.0.0
*/
#include "mfcc.h"
#include "aquila/transform/Dct.h"
#include "aquila/filter/MelFilterBank.h"
namespace Aquila
{
std::vector<double> Mfcc::calculate(SpectrumType spectrum,
std::size_t numFeatures)
{
//auto spectrum = m_fft->fft(source);
Aquila::MelFilterBank bank(44100, m_inputSize);
auto filterOutput = bank.applyAll(spectrum);
Aquila::Dct dct;
return dct.dct(filterOutput, numFeatures);
}
}

82
samplebrain/src/mfcc.h Normal file
View File

@ -0,0 +1,82 @@
/**
* @file Mfcc.h
*
* Calculation of MFCC signal features.
*
* This file is part of the Aquila DSP library.
* Aquila is free software, licensed under the MIT/X11 License. A copy of
* the license is provided with the library in the LICENSE file.
*
* @package Aquila
* @version 3.0.0-dev
* @author Zbigniew Siciarz
* @date 2007-2014
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @since 3.0.0
*/
#ifndef MFCC_H
#define MFCC_H
#include "aquila/global.h"
#include "aquila/transform/FftFactory.h"
#include <jellyfish/fluxa/sample.h>
#include <cstddef>
#include <vector>
namespace Aquila
{
/**
* The Mfcc class implements calculation of MFCC features from input signal.
*
* MFCC coefficients are commonly used in speech recognition. The common
* workflow is to split input signal in frames of equal length and apply
* MFCC calculation to each frame individually. Hence a few assumptions
* were made here:
*
* - a single Mfcc instance can be used only to process signals of equal
* length, for example consecutive frames
* - if you need to handle signals of various lengths, just create new
* Mfcc object per each signal source
*
* The code below is a simplest possible example of how to calculate MFCC
* for each frame of input signal.
*
* FramesCollection frames(data, FRAME_SIZE);
* Mfcc mfcc(FRAME_SIZE);
* for (Frame& frame : frames) {
* auto mfccValues = mfcc.calculate(frame);
* // do something with the calculated values
* }
*
*/
class AQUILA_EXPORT Mfcc
{
public:
/**
* Constructor creates the FFT object to reuse between calculations.
*
* @param inputSize input length (common to all inputs)
*/
Mfcc(std::size_t inputSize):
m_inputSize(inputSize)//, m_fft(FftFactory::getFft(inputSize))
{
}
std::vector<double> calculate(SpectrumType s, std::size_t numFeatures = 12);
private:
/**
* Number of samples in each processed input.
*/
const std::size_t m_inputSize;
/**
* FFT calculator.
*/
//std::shared_ptr<Fft> m_fft;
};
}
#endif // MFCC_H

View File

@ -0,0 +1,100 @@
#include "renderer.h"
#include <iostream>
using namespace spiralcore;
using namespace std;
void renderer::init(brain &source, brain &target, float ratio) {
m_source=source;
m_target=target;
m_render_time=0;
m_render_blocks.clear();
m_ratio = ratio;
}
void renderer::process(u32 nframes, float *buf) {
// get blocks from source for the current buffer
u32 src_shift = m_source.get_block_size()-m_source.get_overlap();
u32 tgt_shift = m_target.get_block_size()-m_target.get_overlap();
u32 tgt_start = m_render_time/(float)tgt_shift;
u32 tgt_end = (m_render_time+nframes)/(float)tgt_shift;
tgt_end++;
// get indices for current buffer
for (u32 tgt_index = tgt_start; tgt_index<tgt_end; tgt_index++) {
u32 time=tgt_index*tgt_shift;
u32 src_index = m_source.search(m_target.get_block(tgt_index), m_ratio);
// put them in the index list
m_render_blocks.push_back(render_block(src_index,time));
}
// render all blocks in list
for (std::list<render_block>::iterator i=m_render_blocks.begin(); i!=m_render_blocks.end(); ++i) {
const sample &pcm=m_source.get_block_pcm(i->m_index);
// get the sample offset into the buffer
s32 offset = i->m_time-m_render_time;
// assume midway through block
s32 block_start = offset;
u32 buffer_start = 0;
if (block_start<0) {
block_start=-block_start;
if (block_start>=pcm.get_length()) i->m_finished=true;
} else { // block is midway through buffer
block_start=0;
buffer_start=offset;
}
if (!i->m_finished) {
// mix in
u32 buffer_pos = buffer_start;
u32 block_pos = block_start;
u32 block_end = block_start+pcm.get_length();
while (block_pos<block_end && buffer_pos<nframes) {
buf[buffer_pos]+=pcm[block_pos];
++buffer_pos;
++block_pos;
}
}
}
// delete old ones
std::list<render_block>::iterator i=m_render_blocks.begin();
std::list<render_block>::iterator ni=m_render_blocks.begin();
while(i!=m_render_blocks.end()) {
ni++;
if (i->m_finished) m_render_blocks.erase(i);
i=ni;
}
m_render_time+=nframes;
}
bool renderer::unit_test() {
brain source;
source.load_sound("test_data/up.wav");
source.init(10,0);
brain target;
target.load_sound("test_data/up.wav");
target.init(10,0);
renderer rr(source,target,1);
float *buf=new float[10];
rr.process(5,buf);
assert(rr.m_render_blocks.size()==1);
rr.process(10,buf);
assert(rr.m_render_blocks.size()==1);
rr.process(20,buf);
assert(rr.m_render_blocks.size()==2);
rr.process(5,buf);
assert(rr.m_render_blocks.size()==1);
target.init(10,5);
rr.process(10,buf);
assert(rr.m_render_blocks.size()==4);
}

View File

@ -0,0 +1,38 @@
#include <list>
#include <jellyfish/fluxa/sample.h>
#include "brain.h"
namespace spiralcore {
class renderer {
public:
renderer(brain &source, brain &target, float ratio) :
m_source(source), m_target(target)
{ init(source,target,ratio); }
void init(brain &source, brain &target, float ratio);
void process(u32 nframes, float *buf);
static bool unit_test();
private:
// realtime stuff
class render_block {
public:
render_block(u32 index, u32 time) :
m_index(index), m_time(time), m_finished(false) {}
u32 m_index;
u32 m_time; // in samples
bool m_finished;
};
brain &m_source;
brain &m_target;
float m_ratio;
std::list<render_block> m_render_blocks;
u32 m_render_time;
};
}