samplebrain/samplebrain/src/renderer.cpp

369 lines
11 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-09 17:50:03 -03:00
#include "renderer.h"
#include <iostream>
using namespace spiralcore;
using namespace std;
2015-07-11 08:29:51 -03:00
void renderer::init(brain &source, brain &target) {
2015-07-11 15:03:05 -03:00
m_volume=1;
2015-07-12 20:26:30 -03:00
m_playing=false;
2015-07-09 17:50:03 -03:00
m_source=source;
m_target=target;
m_target_time=0;
2015-07-09 17:50:03 -03:00
m_render_time=0;
m_n_mix=0;
m_target_mix=0;
2015-07-09 17:50:03 -03:00
m_render_blocks.clear();
m_search_algo=BASIC;
m_slide_error=1;
m_target_index=0;
2015-08-05 18:09:08 -03:00
m_target_counter=0;
2015-08-06 09:39:14 -03:00
m_stretch=1;
2015-07-27 12:17:49 -03:00
m_last_tgt_shift=0;
2015-07-09 17:50:03 -03:00
}
2015-07-09 19:54:05 -03:00
static int ratio_time = 0;
2015-07-27 12:17:49 -03:00
void renderer::reset() {
m_target_time=0;
m_render_time=0;
m_target_index=0;
2015-08-05 18:09:08 -03:00
m_target_counter=0;
2015-07-27 12:17:49 -03:00
m_render_blocks.clear();
2015-08-04 06:14:06 -03:00
m_source.jiggle();
2015-07-27 12:17:49 -03:00
}
2015-08-05 18:09:08 -03:00
2015-07-09 17:50:03 -03:00
void renderer::process(u32 nframes, float *buf) {
2015-07-11 08:29:51 -03:00
if (!m_playing) return;
2015-08-05 18:09:08 -03:00
if (!find_render_blocks(nframes)) return;
render(nframes,buf);
clean_up();
m_render_time+=nframes;
2015-08-06 09:39:14 -03:00
m_target_time+=nframes/(float)m_stretch;
2015-08-05 18:09:08 -03:00
}
bool renderer::find_render_blocks(u32 nframes) {
// get new blocks from source for the current buffer
// where are we phase?
u32 tgt_shift = m_target.get_block_size()-m_target.get_overlap();
u32 tgt_end = (m_target_time+nframes)/(float)tgt_shift;
// stuff has changed - recompute and abort
if (tgt_shift!=m_last_tgt_shift ||
2015-08-06 09:39:14 -03:00
tgt_end>=m_target.get_num_blocks() ||
m_source.get_num_blocks()==0) {
2015-08-05 18:09:08 -03:00
reset();
m_last_tgt_shift = tgt_shift;
// next time...
return false;
}
2015-08-06 09:39:14 -03:00
/* cerr<<"-----------------"<<endl;
cerr<<"tgt start:"<<m_target_index<<endl;
cerr<<"tgt end:"<<tgt_end<<endl;
cerr<<":"<<tgt_end-m_target_index<<endl;
cerr<<"block time "<<m_target_counter*tgt_shift<<endl;
cerr<<"target time "<<m_target_time<<endl;
cerr<<"render time "<<m_render_time<<endl;
cerr<<": "<<(s32)m_render_time-(s32)(m_target_time)<<endl;*/
2015-08-05 18:09:08 -03:00
// search phase
// get indices for current buffer
2015-08-06 09:39:14 -03:00
u32 counter = m_target_index;
2015-08-05 18:09:08 -03:00
//u32 cur_time = m_render_time;
while (counter<=tgt_end) {
u32 time=m_target_counter*tgt_shift;
u32 src_index=0;
switch (m_search_algo) {
case BASIC:
src_index = m_source.search(m_target.get_block(m_target_index), m_search_params);
break;
case REV_BASIC:
src_index = m_source.rev_search(m_target.get_block(m_target_index), m_search_params);
break;
case SYNAPTIC:
case SYNAPTIC_SLIDE:
src_index = m_source.search_synapses(m_target.get_block(m_target_index), m_search_params);
break;
}
if (m_search_algo==SYNAPTIC_SLIDE) {
m_render_blocks.push_back(render_block(src_index,m_target_index,time));
if (m_source.get_current_error()<m_slide_error &&
2015-08-06 09:39:14 -03:00
m_target_counter%m_stretch==0) {
2015-08-05 18:09:08 -03:00
m_target_index++;
2015-08-06 09:39:14 -03:00
//m_target_time+=tgt_shift;
2015-08-05 18:09:08 -03:00
}
m_target_counter++;
} else {
// put them in the index list
m_render_blocks.push_back(render_block(src_index,m_target_index,time));
2015-08-06 09:39:14 -03:00
if (m_target_counter%m_stretch==0) {
2015-08-05 18:09:08 -03:00
m_target_index++;
2015-08-06 09:39:14 -03:00
//m_target_time+=tgt_shift;
2015-08-05 18:09:08 -03:00
}
m_target_counter++;
}
counter++;
}
return true;
}
void renderer::render(u32 nframes, float *buf) {
// render phase
// 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(i->m_index).get_pcm();
const sample &n_pcm=m_source.get_block(i->m_index).get_n_pcm();
const sample &target_pcm=m_target.get_block(i->m_tgt_index).get_pcm();
// get the sample offset into the buffer
s32 offset = i->m_time-m_render_time;
// assume midway through block
u32 block_start = offset;
u32 buffer_start = 0;
if (offset<0) {
block_start=-offset;
if (block_start>=pcm.get_length()) i->m_finished=true;
} else { // block is midway through buffer
block_start=0;
buffer_start=offset;
}
// cerr<<"-----------------"<<endl;
// cerr<<"block start:"<<block_start<<endl;
// cerr<<"buffer start:"<<buffer_start<<endl;
if (!i->m_finished) {
// mix in
u32 buffer_pos = buffer_start;
u32 block_pos = block_start;
u32 block_end = pcm.get_length();
while (block_pos<block_end && buffer_pos<nframes) {
// mix with normalised version
float brain_sample = (pcm[block_pos]*(1-m_n_mix)+
n_pcm[block_pos]*m_n_mix);
// for mixing with target audio
float target_sample = target_pcm[block_pos];
buf[buffer_pos]+=(brain_sample*(1-m_target_mix) +
target_sample*m_target_mix)*0.2*m_volume;
++buffer_pos;
++block_pos;
}
}
}
}
void renderer::clean_up() {
// cleanup phase
// 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;
}
}
void renderer::old_process(u32 nframes, float *buf) {
if (!m_playing) return;
2015-07-11 08:29:51 -03:00
// get new blocks from source for the current buffer
2015-07-09 17:50:03 -03:00
u32 tgt_shift = m_target.get_block_size()-m_target.get_overlap();
u32 tgt_end = (m_target_time+nframes)/(float)tgt_shift;
2015-07-09 18:59:44 -03:00
2015-07-27 12:17:49 -03:00
if (tgt_shift!=m_last_tgt_shift ||
tgt_end>=m_target.get_num_blocks() || m_source.get_num_blocks()==0) {
reset();
m_last_tgt_shift = tgt_shift;
2015-07-09 18:59:44 -03:00
// next time...
return;
}
2015-08-06 09:39:14 -03:00
cerr<<"-----------------"<<endl;
cerr<<"tgt start:"<<m_target_index<<endl;
cerr<<"tgt end:"<<tgt_end<<endl;
cerr<<":"<<tgt_end-m_target_index<<endl;
cerr<<"block time "<<m_target_index*tgt_shift<<endl;
cerr<<"render time "<<m_render_time<<endl;
cerr<<": "<<(s32)m_render_time-(s32)(m_target_index*tgt_shift)<<endl;
2015-07-21 14:13:39 -03:00
// cerr<<"-----------------"<<endl;
// cerr<<"tgt start:"<<m_target_index<<endl;
// cerr<<"tgt end:"<<tgt_end<<endl;
2015-07-09 17:50:03 -03:00
// get indices for current buffer
u32 counter = m_target_index;
//u32 cur_time = m_render_time;
while (counter<=tgt_end) {
u32 time=m_target_index*tgt_shift;
u32 src_index=0;
switch (m_search_algo) {
case BASIC:
src_index = m_source.search(m_target.get_block(m_target_index), m_search_params);
break;
case REV_BASIC:
src_index = m_source.rev_search(m_target.get_block(m_target_index), m_search_params);
break;
case SYNAPTIC:
case SYNAPTIC_SLIDE:
src_index = m_source.search_synapses(m_target.get_block(m_target_index), m_search_params);
break;
}
if (m_search_algo==SYNAPTIC_SLIDE) {
m_render_blocks.push_back(render_block(src_index,m_target_index,time));
if (m_source.get_current_error()<m_slide_error) {
m_target_index++;
}
else{ cerr<<"skip"<<endl; }
2015-07-21 18:28:48 -03:00
} else {
// put them in the index list
m_render_blocks.push_back(render_block(src_index,m_target_index,time));
m_target_index++;
2015-07-21 18:28:48 -03:00
}
counter++;
2015-07-09 17:50:03 -03:00
}
// 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(i->m_index).get_pcm();
const sample &n_pcm=m_source.get_block(i->m_index).get_n_pcm();
const sample &target_pcm=m_target.get_block(i->m_tgt_index).get_pcm();
2015-07-09 17:50:03 -03:00
// get the sample offset into the buffer
s32 offset = i->m_time-m_render_time;
// assume midway through block
2015-07-09 18:59:44 -03:00
u32 block_start = offset;
2015-07-09 17:50:03 -03:00
u32 buffer_start = 0;
2015-07-09 18:59:44 -03:00
if (offset<0) {
block_start=-offset;
2015-07-09 17:50:03 -03:00
if (block_start>=pcm.get_length()) i->m_finished=true;
} else { // block is midway through buffer
block_start=0;
buffer_start=offset;
}
2015-07-09 18:59:44 -03:00
// cerr<<"-----------------"<<endl;
// cerr<<"block start:"<<block_start<<endl;
// cerr<<"buffer start:"<<buffer_start<<endl;
2015-07-09 17:50:03 -03:00
if (!i->m_finished) {
// mix in
u32 buffer_pos = buffer_start;
u32 block_pos = block_start;
2015-07-09 18:59:44 -03:00
u32 block_end = pcm.get_length();
2015-07-09 17:50:03 -03:00
while (block_pos<block_end && buffer_pos<nframes) {
// mix with normalised version
float brain_sample = (pcm[block_pos]*(1-m_n_mix)+
n_pcm[block_pos]*m_n_mix);
// for mixing with target audio
float target_sample = target_pcm[block_pos];
buf[buffer_pos]+=(brain_sample*(1-m_target_mix) +
target_sample*m_target_mix)*0.2*m_volume;
2015-07-09 17:50:03 -03:00
++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;
m_target_time+=nframes;
2015-07-09 17:50:03 -03:00
}
2015-08-05 18:09:08 -03:00
2015-07-09 17:50:03 -03:00
bool renderer::unit_test() {
brain source;
source.load_sound("test_data/up.wav");
2015-07-18 20:34:56 -03:00
source.init(10,0,window::RECTANGLE);
2015-07-09 17:50:03 -03:00
brain target;
target.load_sound("test_data/up.wav");
2015-07-18 20:34:56 -03:00
target.init(10,0,window::RECTANGLE);
2015-07-09 17:50:03 -03:00
2015-07-11 08:29:51 -03:00
renderer rr(source,target);
2015-07-18 20:34:56 -03:00
rr.set_playing(true);
2015-08-03 16:24:49 -03:00
float *buf=new float[400];
2015-07-09 17:50:03 -03:00
rr.process(10,buf);
2015-08-03 16:24:49 -03:00
rr.process(10,buf);
assert(rr.m_render_blocks.size()==2);
2015-07-09 18:59:44 -03:00
rr.process(10,buf);
assert(rr.m_render_blocks.size()==2);
2015-07-18 20:34:56 -03:00
delete[] buf;
buf=new float[20];
2015-07-09 18:59:44 -03:00
rr.process(20,buf);
assert(rr.m_render_blocks.size()==3);
2015-07-09 17:50:03 -03:00
rr.process(5,buf);
assert(rr.m_render_blocks.size()==1);
2015-07-09 17:50:03 -03:00
2015-07-18 20:34:56 -03:00
target.init(10,5,window::RECTANGLE);
2015-07-09 17:50:03 -03:00
rr.process(10,buf);
2015-08-03 16:24:49 -03:00
rr.process(10,buf);
rr.process(10,buf);
rr.process(10,buf);
assert(rr.m_render_blocks.size()==4);
2015-07-18 20:34:56 -03:00
delete[] buf;
2015-07-09 17:50:03 -03:00
}