samplebrain/samplebrain/src/brain.cpp

266 lines
8.0 KiB
C++
Raw Normal View History

2015-07-21 10:58:13 -03:00
// Copyright (C) 2015 Foam Kernow
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2015-07-08 06:24:02 -03:00
#include <iostream>
#include <algorithm>
2015-07-08 06:24:02 -03:00
#include <sndfile.h>
2015-07-21 18:28:48 -03:00
#include <float.h>
2015-07-18 20:34:56 -03:00
#include <jellyfish/audio.h>
2015-07-08 06:24:02 -03:00
#include "brain.h"
#include "status.h"
2015-07-08 06:24:02 -03:00
using namespace std;
using namespace spiralcore;
brain::brain() :
m_current_block_index(0),
m_average_error(0),
m_current_error(0),
m_usage_falloff(0.9)
2015-07-08 06:24:02 -03:00
{
status::update("brain ready...");
2015-07-08 06:24:02 -03:00
}
// load, chop up and add to brain
// todo: add tags
2015-07-11 17:30:16 -03:00
void brain::load_sound(std::string filename) {
2015-07-08 06:24:02 -03:00
SF_INFO sfinfo;
sfinfo.format=0;
SNDFILE* f=sf_open(filename.c_str(), SFM_READ, &sfinfo);
2015-07-11 17:30:16 -03:00
if (f!=NULL) {
sample s(sfinfo.frames);
sf_readf_float(f, s.get_non_const_buffer(), s.get_length());
m_samples.push_back(sound(filename,s));
status::update("loaded %s",filename.c_str());
2015-07-11 17:30:16 -03:00
}
}
void brain::delete_sound(std::string filename) {
for (std::list<sound>::iterator i=m_samples.begin(); i!=m_samples.end(); ++i) {
if (i->m_filename==filename) {
m_samples.erase(i);
status::update("deleted %s",filename.c_str());
2015-07-11 17:30:16 -03:00
return;
}
}
2015-07-08 06:24:02 -03:00
}
// rewrites whole brain
2015-07-18 20:34:56 -03:00
void brain::init(u32 block_size, u32 overlap, window::type t, bool ditchpcm) {
2015-07-08 06:24:02 -03:00
m_blocks.clear();
2015-07-08 06:52:30 -03:00
m_block_size = block_size;
m_overlap = overlap;
2015-07-18 20:34:56 -03:00
m_window.init(block_size);
m_window.set_current_type(t);
u32 count=0;
2015-07-11 17:30:16 -03:00
for (std::list<sound>::iterator i=m_samples.begin(); i!=m_samples.end(); ++i) {
count++;
chop_and_add(i->m_sample, count, ditchpcm);
2015-07-08 06:24:02 -03:00
}
status::update("all samples processed");
2015-07-08 06:24:02 -03:00
}
void brain::chop_and_add(const sample &s, u32 count, bool ditchpcm) {
2015-07-08 06:24:02 -03:00
u32 pos=0;
2015-07-18 20:34:56 -03:00
if (m_overlap>=m_block_size) m_overlap=0;
while (pos+m_block_size-1<s.get_length()) {
status::update("processing sample %d: %d%%",count,(int)(pos/(float)s.get_length()*100));
2015-07-08 06:24:02 -03:00
sample region;
2015-07-18 20:34:56 -03:00
s.get_region(region,pos,pos+m_block_size-1);
m_blocks.push_back(block("",region,44100,m_window,ditchpcm));
pos += (m_block_size-m_overlap);
2015-07-08 06:24:02 -03:00
}
}
2015-07-09 17:48:59 -03:00
const block &brain::get_block(u32 index) const {
2015-07-09 12:16:36 -03:00
return m_blocks[index];
}
2015-07-08 06:52:30 -03:00
static const double usage_factor = 1000000;
2015-07-08 06:24:02 -03:00
// returns index to block
u32 brain::search(const block &target, const search_params &params) {
2015-07-21 18:28:48 -03:00
double closest = FLT_MAX;
2015-07-08 06:24:02 -03:00
u32 closest_index = 0;
u32 index = 0;
2015-07-09 17:48:59 -03:00
for (vector<block>::const_iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) {
2015-07-11 08:29:51 -03:00
double diff = target.compare(*i,params);
2015-07-08 06:24:02 -03:00
if (diff<closest) {
closest=diff;
closest_index = index;
}
++index;
}
deplete_usage();
m_blocks[closest_index].get_usage()+=usage_factor;
2015-07-08 06:24:02 -03:00
return closest_index;
}
2015-07-21 18:28:48 -03:00
// returns index to block
u32 brain::rev_search(const block &target, const search_params &params) {
2015-07-21 18:28:48 -03:00
double furthest = 0;
u32 furthest_index = 0;
u32 index = 0;
for (vector<block>::const_iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) {
double diff = target.compare(*i,params);
if (diff>furthest) {
furthest=diff;
furthest_index = index;
}
++index;
}
deplete_usage();
m_blocks[furthest_index].get_usage()+=usage_factor;
2015-07-21 18:28:48 -03:00
return furthest_index;
}
double brain::calc_average_diff(search_params &params) {
double diff=0;
for (vector<block>::const_iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) {
for (vector<block>::const_iterator j=m_blocks.begin(); j!=m_blocks.end(); ++j) {
diff += j->compare(*i,params);
}
diff/=(double)m_blocks.size();
}
return diff;
}
void brain::build_synapses(search_params &params, double thresh) {
m_average_error = calc_average_diff(params)*thresh;
double err=m_average_error*thresh;
u32 brain_size = m_blocks.size();
u32 outer_index=0;
for (vector<block>::iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) {
u32 index = 0;
status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100));
for (vector<block>::const_iterator j=m_blocks.begin(); j!=m_blocks.end(); ++j) {
if (index!=outer_index) {
double diff = i->compare(*j,params);
if (diff<err) {
i->get_synapse().push_back(index);
}
}
++index;
}
++outer_index;
}
}
u32 brain::search_synapses(const block &target, search_params &params) {
const block &current = get_block(m_current_block_index);
double closest = DBL_MAX;
u32 closest_index = 0;
// find nearest in synaptic connections
// cerr<<"searching "<<current.get_synapse_const().size()<<" connections"<<endl;
for (vector<u32>::const_iterator i=current.get_synapse_const().begin();
i!=current.get_synapse_const().end(); ++i) {
const block &other = get_block(*i);
double diff = target.compare(other,params);
if (diff<closest) {
closest=diff;
closest_index = *i;
}
}
deplete_usage();
m_blocks[m_current_block_index].get_usage()+=usage_factor;
m_current_error = closest;
if (closest_index!=0) {
//cerr<<"usage:"<<m_blocks[closest_index].get_usage()<<endl;
m_current_block_index = closest_index;
}
return m_current_block_index;
}
void brain::deplete_usage() {
for (vector<block>::iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) {
i->get_usage()*=m_usage_falloff;
}
}
2015-07-08 06:24:02 -03:00
// take another brain and rebuild this brain from bits of that one
// (presumably this one is made from a single sample)
/*void brain::resynth(const string &filename, const brain &other, const search_params &params){
2015-07-08 11:06:08 -03:00
sample out((m_block_size-m_overlap)*m_blocks.size());
out.zero();
u32 pos = 0;
u32 count = 0;
2015-07-09 12:16:36 -03:00
cerr<<other.m_blocks.size()<<" brain blocks..."<<endl;
2015-07-09 19:54:05 -03:00
cerr<<endl;
2015-07-09 17:48:59 -03:00
for (vector<block>::iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) {
2015-07-09 12:16:36 -03:00
cerr<<'\r';
cerr<<"searching: "<<count/float(m_blocks.size())*100;
2015-07-11 08:29:51 -03:00
u32 index = other.search(*i, params);
2015-07-09 12:16:36 -03:00
//cerr<<index<<endl;
out.mul_mix(other.get_block_pcm(index),pos,0.2);
2015-07-08 11:06:08 -03:00
if (count%1000==0) {
2015-07-18 20:34:56 -03:00
audio_device::save_sample(filename,out);
2015-07-08 11:06:08 -03:00
}
++count;
pos += (m_block_size-m_overlap);
2015-07-08 06:52:30 -03:00
}
2015-07-18 20:34:56 -03:00
audio_device::save_sample(filename,out);
2015-07-08 06:24:02 -03:00
}
*/
2015-07-08 06:24:02 -03:00
bool brain::unit_test() {
brain b;
assert(b.m_samples.size()==0);
assert(b.m_blocks.size()==0);
2015-07-11 17:30:16 -03:00
b.load_sound("test_data/100f32.wav");
b.load_sound("test_data/100i16.wav");
2015-07-08 06:24:02 -03:00
assert(b.m_samples.size()==2);
2015-07-18 20:34:56 -03:00
b.init(10, 0, window::RECTANGLE);
2015-07-08 06:24:02 -03:00
assert(b.m_blocks.size()==20);
2015-07-18 20:34:56 -03:00
b.init(10, 5, window::RECTANGLE);
2015-07-08 06:24:02 -03:00
assert(b.m_samples.size()==2);
assert(b.m_blocks.size()==38);
2015-07-18 20:34:56 -03:00
b.init(20, 5, window::RECTANGLE);
2015-07-08 06:24:02 -03:00
assert(b.m_samples.size()==2);
assert(b.m_blocks.size()==12);
2015-07-18 20:34:56 -03:00
2015-07-08 11:06:08 -03:00
// replicate brains
2015-07-08 06:24:02 -03:00
brain b2;
2015-07-08 11:06:08 -03:00
b2.load_sound("test_data/up.wav");
brain b3;
b3.load_sound("test_data/up.wav");
2015-07-18 20:34:56 -03:00
b2.init(512, 0, window::BLACKMAN);
b3.init(512, 0, window::BLACKMAN);
2015-07-11 08:29:51 -03:00
search_params p(1,0,0,100,0);
2015-07-11 08:29:51 -03:00
assert(b3.search(b2.m_blocks[0],p)==0);
assert(b3.search(b2.m_blocks[9],p)==9);
assert(b3.search(b2.m_blocks[19],p)==19);
assert(b3.search(b2.m_blocks[29],p)==29);
2015-07-08 11:06:08 -03:00
// sample r = b2.resynth(b,1);
// assert(r.get_length()==200);
2015-07-08 06:24:02 -03:00
return true;
}