diff --git a/samplebrain/interface/samplebrain.ui b/samplebrain/interface/samplebrain.ui index 2954439..632f97f 100644 --- a/samplebrain/interface/samplebrain.ui +++ b/samplebrain/interface/samplebrain.ui @@ -7,11 +7,11 @@ 0 0 910 - 669 + 671 - samplebrain 0.16 + samplebrain 0.17 @@ -865,6 +865,18 @@ + + + + + Comic Sans MS + + + + use mic input + + + @@ -1384,7 +1396,24 @@ - + + + + + + + + + 0 + 0 + + + + This program is free software made in Cornwall by <a href="http://fo.am/kernow">FoAM Kernow</a> + + + + @@ -2407,6 +2436,22 @@ + + mic + clicked(bool) + MainWindow + mic(bool) + + + 404 + 601 + + + 454 + 335 + + + play_slot() @@ -2463,5 +2508,6 @@ load_sounds() select_all() select_none() + mic(bool) diff --git a/samplebrain/qt/MainWindow.h b/samplebrain/qt/MainWindow.h index 16b1aa3..71c1005 100644 --- a/samplebrain/qt/MainWindow.h +++ b/samplebrain/qt/MainWindow.h @@ -239,6 +239,7 @@ private slots: void brain_shape(int n) { send_process_osc("/window_type","i",n); } void target_shape(int n) { send_process_osc("/target_window_type","i",n); } + void mic(bool n) { send_audio_osc("/mic","i",(int)n); } void record() { if (m_save_wav=="") { diff --git a/samplebrain/qt/audio_thread.cpp b/samplebrain/qt/audio_thread.cpp index 5893e63..2ed5fd0 100644 --- a/samplebrain/qt/audio_thread.cpp +++ b/samplebrain/qt/audio_thread.cpp @@ -25,12 +25,14 @@ audio_thread::audio_thread(process_thread &p) : m_osc("8888"), m_process_thread(p), m_brain_mutex(p.m_brain_mutex), - m_stereo_mode(false) + m_stereo_mode(false), + m_mic_mode(false) { start_audio(); pthread_mutex_lock(m_brain_mutex); m_left_renderer = new renderer(p.m_source,p.m_left_target); m_right_renderer = new renderer(p.m_source,p.m_right_target); + m_block_stream = new block_stream(); pthread_mutex_unlock(m_brain_mutex); m_osc.run(); } @@ -54,13 +56,15 @@ void audio_thread::run_audio(void* c, unsigned int frames) { if (state) { audio_thread *at = (audio_thread*)c; at->m_audio_device->left_out.zero(); - at->process(at->m_audio_device->left_out, + at->process(at->m_audio_device->left_in, + at->m_audio_device->right_in, + at->m_audio_device->left_out, at->m_audio_device->right_out); at->m_audio_device->maybe_record(); } } -void audio_thread::process(sample &s, sample &s2) { +void audio_thread::process(sample &left_in, sample &right_in, sample &left_out, sample &right_out) { command_ring_buffer::command cmd; while (m_osc.get(cmd)) { @@ -162,16 +166,31 @@ void audio_thread::process(sample &s, sample &s2) { m_left_renderer->reset(); m_right_renderer->reset(); } + if (name=="/mic") { + m_mic_mode = cmd.get_int(0); + } } - s.zero(); - s2.zero(); + left_out.zero(); + right_out.zero(); if (!pthread_mutex_trylock(m_brain_mutex)) { - m_left_renderer->process(s.get_length(),s.get_non_const_buffer()); + + block_stream *bs=NULL; + + if (m_mic_mode) { + m_block_stream->process(left_in,right_in); + bs = m_block_stream; + } + + m_left_renderer->process(left_out.get_length(), + left_out.get_non_const_buffer(), + bs); if (m_stereo_mode) { - m_right_renderer->process(s2.get_length(),s2.get_non_const_buffer()); + m_right_renderer->process(right_out.get_length(), + right_out.get_non_const_buffer(), + bs); } else { - s2=s; + right_out=left_out; } pthread_mutex_unlock(m_brain_mutex); } else { diff --git a/samplebrain/qt/audio_thread.h b/samplebrain/qt/audio_thread.h index fca8b4b..6d8db0e 100644 --- a/samplebrain/qt/audio_thread.h +++ b/samplebrain/qt/audio_thread.h @@ -17,6 +17,7 @@ #include "jellyfish/OSC_server.h" #include "process_thread.h" #include "renderer.h" +#include "block_stream.h" #include "jellyfish/audio.h" #pragma once @@ -28,13 +29,14 @@ public: audio_thread(process_thread &p); ~audio_thread(); - void process(sample &left, sample &right); + void process(sample &left_in, sample &right_in, sample &left_out, sample &right_out); static void run_audio(void* c, unsigned int frames); audio_device *m_audio_device; renderer *m_left_renderer; renderer *m_right_renderer; + block_stream *m_block_stream; private: void start_audio(); @@ -43,6 +45,7 @@ private: process_thread &m_process_thread; pthread_mutex_t* m_brain_mutex; bool m_stereo_mode; + bool m_mic_mode; }; } diff --git a/samplebrain/qt/generated/ui_samplebrain.h b/samplebrain/qt/generated/ui_samplebrain.h index 87c0f98..e12e877 100644 --- a/samplebrain/qt/generated/ui_samplebrain.h +++ b/samplebrain/qt/generated/ui_samplebrain.h @@ -1,13 +1,13 @@ /******************************************************************************** -** Form generated from reading UI file 'samplebrainr24659.ui' +** Form generated from reading UI file 'samplebrainr15646.ui' ** ** Created by: Qt User Interface Compiler version 4.8.6 ** ** WARNING! All changes made in this file will be lost when recompiling UI file! ********************************************************************************/ -#ifndef SAMPLEBRAINR24659_H -#define SAMPLEBRAINR24659_H +#ifndef SAMPLEBRAINR15646_H +#define SAMPLEBRAINR15646_H #include #include @@ -99,6 +99,7 @@ public: QLabel *label_14; QComboBox *comboBoxTargetShape; QPushButton *pushButtonGenerateTarget; + QCheckBox *mic; QLabel *label_23; QHBoxLayout *horizontalLayout_22; QLabel *label_31; @@ -143,7 +144,9 @@ public: QSpacerItem *verticalSpacer_2; QWidget *netTab; QHBoxLayout *horizontalLayout_15; + QVBoxLayout *verticalLayout_7; QVBoxLayout *netContainer; + QLabel *label_4; QHBoxLayout *horizontalLayout_12; QPushButton *pushButtonPlay; QPushButton *pushButtonStop; @@ -161,7 +164,7 @@ public: { if (MainWindow->objectName().isEmpty()) MainWindow->setObjectName(QString::fromUtf8("MainWindow")); - MainWindow->resize(910, 669); + MainWindow->resize(910, 671); centralwidget = new QWidget(MainWindow); centralwidget->setObjectName(QString::fromUtf8("centralwidget")); verticalLayout_4 = new QVBoxLayout(centralwidget); @@ -588,6 +591,14 @@ public: verticalLayout_6->addWidget(pushButtonGenerateTarget); + mic = new QCheckBox(controlTab); + mic->setObjectName(QString::fromUtf8("mic")); + QFont font3; + font3.setFamily(QString::fromUtf8("Comic Sans MS")); + mic->setFont(font3); + + verticalLayout_6->addWidget(mic); + label_23 = new QLabel(controlTab); label_23->setObjectName(QString::fromUtf8("label_23")); label_23->setFont(font1); @@ -852,10 +863,25 @@ public: netTab->setObjectName(QString::fromUtf8("netTab")); horizontalLayout_15 = new QHBoxLayout(netTab); horizontalLayout_15->setObjectName(QString::fromUtf8("horizontalLayout_15")); + verticalLayout_7 = new QVBoxLayout(); + verticalLayout_7->setObjectName(QString::fromUtf8("verticalLayout_7")); netContainer = new QVBoxLayout(); netContainer->setObjectName(QString::fromUtf8("netContainer")); - horizontalLayout_15->addLayout(netContainer); + verticalLayout_7->addLayout(netContainer); + + label_4 = new QLabel(netTab); + label_4->setObjectName(QString::fromUtf8("label_4")); + QSizePolicy sizePolicy3(QSizePolicy::Preferred, QSizePolicy::Maximum); + sizePolicy3.setHorizontalStretch(0); + sizePolicy3.setVerticalStretch(0); + sizePolicy3.setHeightForWidth(label_4->sizePolicy().hasHeightForWidth()); + label_4->setSizePolicy(sizePolicy3); + + verticalLayout_7->addWidget(label_4); + + + horizontalLayout_15->addLayout(verticalLayout_7); tabWidget->addTab(netTab, QString()); @@ -1000,6 +1026,7 @@ public: QObject::connect(pushButtonLoadSounds, SIGNAL(released()), MainWindow, SLOT(load_sounds())); QObject::connect(toolButtonAll, SIGNAL(released()), MainWindow, SLOT(select_all())); QObject::connect(toolButtonNone, SIGNAL(released()), MainWindow, SLOT(select_none())); + QObject::connect(mic, SIGNAL(clicked(bool)), MainWindow, SLOT(mic(bool))); tabWidget->setCurrentIndex(0); @@ -1009,7 +1036,7 @@ public: void retranslateUi(QMainWindow *MainWindow) { - MainWindow->setWindowTitle(QApplication::translate("MainWindow", "samplebrain 0.16", 0, QApplication::UnicodeUTF8)); + MainWindow->setWindowTitle(QApplication::translate("MainWindow", "samplebrain 0.17", 0, QApplication::UnicodeUTF8)); label_19->setText(QApplication::translate("MainWindow", "brain tweaks", 0, QApplication::UnicodeUTF8)); label_6->setText(QApplication::translate("MainWindow", "fft / mfcc", 0, QApplication::UnicodeUTF8)); #ifndef QT_NO_TOOLTIP @@ -1107,6 +1134,7 @@ public: << QApplication::translate("MainWindow", "rectangle", 0, QApplication::UnicodeUTF8) ); pushButtonGenerateTarget->setText(QApplication::translate("MainWindow", "(re)generate blocks", 0, QApplication::UnicodeUTF8)); + mic->setText(QApplication::translate("MainWindow", "use mic input", 0, QApplication::UnicodeUTF8)); label_23->setText(QApplication::translate("MainWindow", "mix", 0, QApplication::UnicodeUTF8)); label_31->setText(QApplication::translate("MainWindow", "autotune", 0, QApplication::UnicodeUTF8)); #ifndef QT_NO_TOOLTIP @@ -1145,6 +1173,7 @@ public: pushButtonLoadBrain->setText(QApplication::translate("MainWindow", "load brain", 0, QApplication::UnicodeUTF8)); pushButtonSaveBrain->setText(QApplication::translate("MainWindow", "save brain", 0, QApplication::UnicodeUTF8)); tabWidget->setTabText(tabWidget->indexOf(controlTab), QApplication::translate("MainWindow", "search", 0, QApplication::UnicodeUTF8)); + label_4->setText(QApplication::translate("MainWindow", "This program is free software made in Cornwall by FoAM Kernow", 0, QApplication::UnicodeUTF8)); tabWidget->setTabText(tabWidget->indexOf(netTab), QApplication::translate("MainWindow", "net", 0, QApplication::UnicodeUTF8)); pushButtonPlay->setText(QString()); pushButtonStop->setText(QString()); @@ -1163,4 +1192,4 @@ namespace Ui { QT_END_NAMESPACE -#endif // SAMPLEBRAINR24659_H +#endif // SAMPLEBRAINR15646_H diff --git a/samplebrain/qt/process_thread.cpp b/samplebrain/qt/process_thread.cpp index e00f944..4044e21 100644 --- a/samplebrain/qt/process_thread.cpp +++ b/samplebrain/qt/process_thread.cpp @@ -23,176 +23,181 @@ using namespace spiralcore; using namespace std; static void _process(void *c) { - process_thread *p=(process_thread*)c; - p->process(); + process_thread *p=(process_thread*)c; + p->process(); } process_thread::process_thread() : - m_osc("8889"), - m_source_block_size(3000), - m_source_overlap(0.75), - m_target_block_size(3000), - m_target_overlap(0.75), - m_window_type(window::DODGY), - m_target_window_type(window::DODGY) + m_osc("8889"), + m_source_block_size(3000), + m_source_overlap(0.75), + m_target_block_size(3000), + m_target_overlap(0.75), + m_window_type(window::DODGY), + m_target_window_type(window::DODGY) { - m_brain_mutex = new pthread_mutex_t; - pthread_mutex_init(m_brain_mutex,NULL); - m_osc.run(); - - // start the processing thread - m_thread = new pthread_t; - pthread_create(m_thread,NULL,(void*(*)(void*))_process,this); + m_brain_mutex = new pthread_mutex_t; + pthread_mutex_init(m_brain_mutex,NULL); + m_osc.run(); + + // start the processing thread + m_thread = new pthread_t; + pthread_create(m_thread,NULL,(void*(*)(void*))_process,this); } process_thread::~process_thread() { - pthread_cancel(*m_thread); - delete m_brain_mutex; + pthread_cancel(*m_thread); + delete m_brain_mutex; } void process_thread::process() { - command_ring_buffer::command cmd; + command_ring_buffer::command cmd; - while(true) { - while (m_osc.get(cmd)) { - string name = cmd.m_name; - //cerr<reset(); - m_right_renderer->reset(); - pthread_mutex_unlock(m_brain_mutex); - } - if (name=="/load_target") { - pthread_mutex_lock(m_brain_mutex); - m_left_target.clear_sounds(); - m_left_target.load_sound(cmd.get_string(0),brain::LEFT); - m_right_target.clear_sounds(); - m_right_target.load_sound(cmd.get_string(0),brain::RIGHT); - pthread_mutex_unlock(m_brain_mutex); - } - if (name=="/target_block_size") { - m_target_block_size = cmd.get_int(0); - } - if (name=="/target_overlap") { - m_target_overlap = m_target_block_size*cmd.get_float(0); - } - if (name=="/generate_target") { - pthread_mutex_lock(m_brain_mutex); - m_left_target.init(m_target_block_size, m_target_overlap, m_target_window_type); - m_right_target.init(m_target_block_size, m_target_overlap, m_target_window_type); - pthread_mutex_unlock(m_brain_mutex); - } - if (name=="/window_type") { - m_window_type=(window::type)cmd.get_int(0); - } - if (name=="/target_window_type") { - m_target_window_type=(window::type)cmd.get_int(0); - } - if (name=="/load_brain") { - load_source(cmd.get_string(0)); - } - if (name=="/save_brain") { - save_source(cmd.get_string(0)); - } - if (name=="/load_session") { - load_session(cmd.get_string(0)); - } - if (name=="/save_session") { - save_session(cmd.get_string(0)); - } - } - usleep(500); + while(true) { + while (m_osc.get(cmd)) { + string name = cmd.m_name; + //cerr<reset(); + m_right_renderer->reset(); + pthread_mutex_unlock(m_brain_mutex); + } + if (name=="/load_target") { + pthread_mutex_lock(m_brain_mutex); + m_left_target.clear_sounds(); + m_left_target.load_sound(cmd.get_string(0),brain::LEFT); + m_right_target.clear_sounds(); + m_right_target.load_sound(cmd.get_string(0),brain::RIGHT); + pthread_mutex_unlock(m_brain_mutex); + } + if (name=="/target_block_size") { + m_target_block_size = cmd.get_int(0); + m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type); + } + if (name=="/target_overlap") { + m_target_overlap = m_target_block_size*cmd.get_float(0); + m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type); + } + if (name=="/generate_target") { + pthread_mutex_lock(m_brain_mutex); + m_left_target.init(m_target_block_size, m_target_overlap, m_target_window_type); + m_right_target.init(m_target_block_size, m_target_overlap, m_target_window_type); + // probably elsewhere + m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type); + pthread_mutex_unlock(m_brain_mutex); + } + if (name=="/window_type") { + m_window_type=(window::type)cmd.get_int(0); + } + if (name=="/target_window_type") { + m_target_window_type=(window::type)cmd.get_int(0); + m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type); + } + if (name=="/load_brain") { + load_source(cmd.get_string(0)); + } + if (name=="/save_brain") { + save_source(cmd.get_string(0)); + } + if (name=="/load_session") { + load_session(cmd.get_string(0)); + } + if (name=="/save_session") { + save_session(cmd.get_string(0)); + } } + usleep(500); + } } void process_thread::load_source(const std::string &filename) { - pthread_mutex_lock(m_brain_mutex); - m_source.clear(); - ifstream ifs(filename.c_str(),ios::binary); - ifs||m_source; - ifs.close(); - pthread_mutex_unlock(m_brain_mutex); + pthread_mutex_lock(m_brain_mutex); + m_source.clear(); + ifstream ifs(filename.c_str(),ios::binary); + ifs||m_source; + ifs.close(); + pthread_mutex_unlock(m_brain_mutex); } void process_thread::save_source(const std::string &filename) { - pthread_mutex_lock(m_brain_mutex); - ofstream ofs(filename.c_str(),ios::binary); - ofs||m_source; - ofs.close(); - pthread_mutex_unlock(m_brain_mutex); + pthread_mutex_lock(m_brain_mutex); + ofstream ofs(filename.c_str(),ios::binary); + ofs||m_source; + ofs.close(); + pthread_mutex_unlock(m_brain_mutex); } // remember to change GUI side to match in MainWindow.cpp void process_thread::load_session(const std::string &filename) { - pthread_mutex_lock(m_brain_mutex); - m_source.clear(); - m_left_target.clear(); - m_right_target.clear(); - ifstream ifs(filename.c_str(),ios::binary); - u32 version=0; - ifs||version; - ifs||(*m_left_renderer); - ifs||(*m_right_renderer); - ifs||m_source_block_size||m_source_overlap; - ifs||m_target_block_size||m_target_overlap; - ifs||m_window_type||m_target_window_type; + pthread_mutex_lock(m_brain_mutex); + m_source.clear(); + m_left_target.clear(); + m_right_target.clear(); + ifstream ifs(filename.c_str(),ios::binary); + u32 version=0; + ifs||version; + ifs||(*m_left_renderer); + ifs||(*m_right_renderer); + ifs||m_source_block_size||m_source_overlap; + ifs||m_target_block_size||m_target_overlap; + ifs||m_window_type||m_target_window_type; - cerr<<"loading window type session "< #pragma once @@ -30,9 +31,11 @@ public: pthread_mutex_t* m_brain_mutex; - void register_renderer(renderer *lr, renderer *rr) { + void register_renderer(renderer *lr, renderer *rr, block_stream *bs) { m_left_renderer=lr; m_right_renderer=rr; + m_block_stream=bs; + m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type); } void process(); @@ -59,6 +62,7 @@ private: // only use in mutex obvs... renderer *m_left_renderer; renderer *m_right_renderer; + block_stream *m_block_stream; }; } diff --git a/samplebrain/qt/qtmain.cpp b/samplebrain/qt/qtmain.cpp index 4a204c3..c2571a8 100644 --- a/samplebrain/qt/qtmain.cpp +++ b/samplebrain/qt/qtmain.cpp @@ -38,7 +38,7 @@ int main( int argc , char *argv[] ){ process_thread pt; audio_thread at(pt); - pt.register_renderer(at.m_left_renderer, at.m_right_renderer); + pt.register_renderer(at.m_left_renderer, at.m_right_renderer, at.m_block_stream); return app.exec(); } diff --git a/samplebrain/qt/samplebrain.pro b/samplebrain/qt/samplebrain.pro index 2e9b4d9..9a91676 100644 --- a/samplebrain/qt/samplebrain.pro +++ b/samplebrain/qt/samplebrain.pro @@ -3,7 +3,7 @@ ###################################################################### TEMPLATE = app -TARGET = +TARGET = samplebrain DEPENDPATH += . 2 INCLUDEPATH += . 2 @@ -27,6 +27,7 @@ SOURCES += MainWindow.cpp \ ../src/search_params.cpp \ ../src/status.cpp \ ../src/window.cpp \ + ../src/block_stream.cpp \ ../src/aquila/filter/MelFilterBank.cpp \ ../src/aquila/filter/MelFilter.cpp \ ../src/aquila/transform/Dct.cpp \ @@ -41,7 +42,7 @@ SOURCES += MainWindow.cpp \ INCLUDEPATH += ../src LIBS += -L.. -lportaudio -lfftw3 -lsndfile -llo -ldl -lpthread -lm -#CONFIG+=debug +CONFIG+=debug QMAKE_CXXFLAGS += -Wall -Wno-unused -std=c++11 -DDONT_USE_FLUXA_GRAPH diff --git a/samplebrain/src/block.cpp b/samplebrain/src/block.cpp index a611a18..aeedbaf 100644 --- a/samplebrain/src/block.cpp +++ b/samplebrain/src/block.cpp @@ -89,6 +89,7 @@ block::block(u64 id, const string &filename, const sample &pcm, u32 rate, const w.run(m_n_pcm); process(m_n_pcm,m_n_fft,m_n_mfcc,m_n_dominant_freq); + // don't need to keep pcm for the target if (ditchpcm) { m_pcm.clear(); m_n_pcm.clear(); @@ -96,8 +97,7 @@ block::block(u64 id, const string &filename, const sample &pcm, u32 rate, const } -void block::init_fft(u32 block_size) -{ +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,100); @@ -148,6 +148,7 @@ double block::_compare(const sample &fft_a, const sample &mfcc_a, u32 fft_start = params.m_fft1_start; u32 fft_end = fmin(params.m_fft1_end,m_fft.get_length()); + // first check for only fft if (params.m_ratio==0) { for (u32 i=fft_start; i +#include "block_stream.h" + +using namespace spiralcore; +using namespace std; + +#define BUFFER_SIZE 4096*10 +#define MAX_BLOCKS 200 + +block_stream::block_stream() : + m_ready(false), + m_block_index(0), + m_block_position(0), + m_buffer_position(0), + m_buffer(BUFFER_SIZE), + m_block_index_offset(0) +{ +} + +block_stream::~block_stream() {} + +void block_stream::init(u32 block_size, u32 overlap, window::type t, bool ditchpcm) { + m_block_size=block_size; + m_overlap=overlap; + m_block_index=0; + m_block_position=0; + m_buffer_position=0; + + if (m_overlap>=m_block_size) m_overlap=0; + cerr<m_buffer.get_length()) { + m_buffer_position=0; + } + + // time to make a new block + if (m_block_position>m_block_size-m_overlap) { + sample region; + // m_buffer_pos-m_block_size can be negative to deal + // with the buffer wrapping... + //cerr<<(s32)(m_buffer_position-m_block_size)<<" to "<MAX_BLOCKS) { + m_blocks.erase(m_blocks.begin()); + m_block_index_offset++; + } + } + + m_block_position++; + } + cerr<<"num blocks: "< +#include "window.h" +#include "block.h" +#include "block_source.h" + +#ifndef BLOCK_STREAM +#define BLOCK_STREAM + +namespace spiralcore { + + // the block stream takes incoming audio and chops it up into blocks + // in realtime, for providing them to the renderer (in place of a + // source brain) +class block_stream : public block_source { + public: + block_stream(); + virtual ~block_stream(); + + void init(u32 block_size, u32 overlap, window::type t, bool ditchpcm=false); + + // for the moment ignores right channel + void process(const sample &left, const sample &right); + virtual const block &get_block(u32 index) const; + virtual u32 get_num_blocks() const { return UINT_MAX; } + + u32 last_block_index() const { return m_block_index_offset+m_blocks.size(); } + + private: + + bool m_ready; + + u32 m_block_index; + u32 m_block_position; + u32 m_buffer_position; + sample m_buffer; + + window m_window; + + u32 m_block_index_offset; + vector m_blocks; + +}; + +} + +#endif diff --git a/samplebrain/src/brain.cpp b/samplebrain/src/brain.cpp index b67e565..257dfdc 100644 --- a/samplebrain/src/brain.cpp +++ b/samplebrain/src/brain.cpp @@ -29,58 +29,58 @@ static const u32 NUM_FIXED_SYNAPSES = 1000; static const double usage_factor = 1000; brain::brain() : - m_current_block_index(0), - m_current_error(0), - m_average_error(0), - m_usage_falloff(0.9) + m_current_block_index(0), + m_current_error(0), + m_average_error(0), + m_usage_falloff(0.9) { - status::update("brain ready..."); + status::update("brain ready..."); } // load, chop up and add to brain // todo: add tags void brain::load_sound(std::string filename, stereo_mode mode) { - SF_INFO sfinfo; - sfinfo.format=0; - SNDFILE* f=sf_open(filename.c_str(), SFM_READ, &sfinfo); - if (f!=NULL) { - sample s(sfinfo.frames); - float *temp = new float[sfinfo.channels * sfinfo.frames]; + SF_INFO sfinfo; + sfinfo.format=0; + SNDFILE* f=sf_open(filename.c_str(), SFM_READ, &sfinfo); + if (f!=NULL) { + sample s(sfinfo.frames); + float *temp = new float[sfinfo.channels * sfinfo.frames]; - sf_read_float(f, temp, sfinfo.channels * sfinfo.frames); + sf_read_float(f, temp, sfinfo.channels * sfinfo.frames); - if (mode==MIX) { - for(u32 i=0; i1) si++; - s[i]=temp[si]; - } - } - - delete[] temp; - m_samples.push_back(sound(filename,s)); - status::update("loaded %s",filename.c_str()); + if (mode==MIX) { + for(u32 i=0; i1) si++; + s[i]=temp[si]; + } } + + delete[] temp; + m_samples.push_back(sound(filename,s)); + status::update("loaded %s",filename.c_str()); + } } void brain::delete_sound(std::string filename) { - for (auto 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()); - return; - } + for (auto 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()); + return; } - recompute_sample_sections(); + } + recompute_sample_sections(); } void brain::activate_sound(std::string filename, bool active) { @@ -91,33 +91,32 @@ void brain::activate_sound(std::string filename, bool active) { } } - void brain::clear() { - m_blocks.clear(); - m_samples.clear(); - m_active_sounds.clear(); + m_blocks.clear(); + m_samples.clear(); + m_active_sounds.clear(); } // rewrites whole brain void brain::init(u32 block_size, u32 overlap, window::type t, bool ditchpcm) { - m_blocks.clear(); - m_block_size = block_size; - m_overlap = overlap; - m_window.init(block_size); - m_window.set_current_type(t); - u32 count=0; - for (auto &s:m_samples) { - status::sound_item(s.m_filename,"lightgrey"); - } - for (auto &s:m_samples) { - status::sound_item(s.m_filename,"yellow"); - count++; - chop_and_add(s, count, ditchpcm); - if (count%2==0) status::sound_item(s.m_filename,"lightblue"); - else status::sound_item(s.m_filename,"pink"); - } - status::sound_item_refresh(); - status::update("all samples processed"); + m_blocks.clear(); + m_block_size = block_size; + m_overlap = overlap; + m_window.init(block_size); + m_window.set_current_type(t); + u32 count=0; + for (auto &s:m_samples) { + status::sound_item(s.m_filename,"lightgrey"); + } + for (auto &s:m_samples) { + status::sound_item(s.m_filename,"yellow"); + count++; + chop_and_add(s, count, ditchpcm); + if (count%2==0) status::sound_item(s.m_filename,"lightblue"); + else status::sound_item(s.m_filename,"pink"); + } + status::sound_item_refresh(); + status::update("all samples processed"); } void brain::chop_and_add(sound &s, u32 count, bool ditchpcm) { @@ -158,7 +157,7 @@ void brain::recompute_sample_sections() { } const block &brain::get_block(u32 index) const { - return m_blocks[index]; + return m_blocks[index]; } // helper to do the stickyness comparison and sort out current_block_index @@ -167,14 +166,14 @@ u32 brain::stickify(const block &target, u32 closest_index, f32 dist, const sear // if we have stickyness turned on and the next block exists if (params.m_stickyness>0 && next_indexfurthest) { - furthest=diff; - furthest_index = i; - } - } + double furthest = 0; + u32 furthest_index = 0; + // check each sample section + for (auto &s : m_samples) { + if (s.m_enabled) { // are we turned on? + // loop through indexes for this section + for (u32 i=s.m_start; ifurthest) { + furthest=diff; + furthest_index = i; + } } } - deplete_usage(); - m_blocks[furthest_index].get_usage()+=usage_factor; - m_current_block_index = furthest_index; + } + deplete_usage(); + m_blocks[furthest_index].get_usage()+=usage_factor; + m_current_block_index = furthest_index; - return furthest_index; + return furthest_index; } // really slow - every to every comparison of blocks calculating average distance double brain::calc_average_diff(search_params ¶ms) { - double diff=0; - for (auto &i:m_blocks) { - for (auto &j:m_blocks) { - diff += j.compare(i,params); - } - diff/=(double)m_blocks.size(); + double diff=0; + for (auto &i:m_blocks) { + for (auto &j:m_blocks) { + diff += j.compare(i,params); } - return diff; + diff/=(double)m_blocks.size(); + } + return diff; } void brain::build_synapses_thresh(search_params ¶ms, 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 (auto &i : m_blocks) { - u32 index = 0; - status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100)); - for (auto &j : m_blocks) { - if (index!=outer_index) { - // collect connections that are under threshold in closeness - double diff = i.compare(j,params); - if (diff=m_blocks.size()) num_synapses=m_blocks.size()-1; + //m_average_error = calc_average_diff(params)*thresh; + u32 brain_size = m_blocks.size(); + u32 outer_index = 0; + u32 num_synapses = NUM_FIXED_SYNAPSES; + if (num_synapses>=m_blocks.size()) num_synapses=m_blocks.size()-1; - for (auto &i:m_blocks) { - status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100)); - u32 index = 0; - vector> collect; + for (auto &i:m_blocks) { + status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100)); + u32 index = 0; + vector> collect; - // collect comparisons to all other blocks - for (auto &j:m_blocks) { - assert(index(index,diff)); - } - ++index; - } - - // sort them by closeness - sort(collect.begin(),collect.end(), - [](const pair &a, - const pair &b) -> bool { - return a.second(index,diff)); + } + ++index; } - status::update("Done: %d synapses grown for %d blocks",num_synapses*brain_size,brain_size); + + // sort them by closeness + sort(collect.begin(),collect.end(), + [](const pair &a, + const pair &b) -> bool { + return a.second0) { - m_current_block_index=rand()%m_blocks.size(); - } else { - m_current_block_index=0; - } + if (m_blocks.size()>0) { + m_current_block_index=rand()%m_blocks.size(); + } else { + m_current_block_index=0; + } } bool brain::is_block_active(u32 index) { @@ -321,164 +320,164 @@ bool brain::is_block_active(u32 index) { } u32 brain::search_synapses(const block &target, search_params ¶ms) { - const block ¤t = get_block(m_current_block_index); - double closest = DBL_MAX; - u32 closest_index = 0; + const block ¤t = get_block(m_current_block_index); + double closest = DBL_MAX; + u32 closest_index = 0; - // find nearest in synaptic connections - if (current.get_synapse_const().size()params.m_num_synapses); + // find nearest in synaptic connections + if (current.get_synapse_const().size()params.m_num_synapses); - u32 synapse_count=0; - // use m_num_synapses to restrict search - // only makes sense when ordered by closeness in fixed mode - vector::const_iterator i=current.get_synapse_const().begin(); - while (i!=current.get_synapse_const().end() && - synapse_count::const_iterator i=current.get_synapse_const().begin(); + while (i!=current.get_synapse_const().end() && + synapse_count::iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) { - i->get_usage()*=m_usage_falloff; - } + for (vector::iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) { + i->get_usage()*=m_usage_falloff; + } } // 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 ¶ms){ - sample out((m_block_size-m_overlap)*m_blocks.size()); - out.zero(); - u32 pos = 0; - u32 count = 0; - cerr<::iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) { - cerr<<'\r'; - cerr<<"searching: "<::iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) { + cerr<<'\r'; + cerr<<"searching: "<0) { - s||b.m_num_blocks||b.m_start||b.m_end||b.m_enabled; - } - return s; + u32 version=1; + string id("brain::sound"); + s||id||version; + s||b.m_filename||b.m_sample; + if (version>0) { + s||b.m_num_blocks||b.m_start||b.m_end||b.m_enabled; + } + return s; } ios &spiralcore::operator||(ios &s, brain &b) { - u32 version=1; - string id("brain"); - // changes here need to be reflected in interface loading - s||id||version; - stream_vector(s,b.m_blocks); - stream_list(s,b.m_samples); - s||b.m_block_size||b.m_overlap||b.m_window; - s||b.m_current_block_index||b.m_current_error|| - b.m_average_error||b.m_usage_falloff; - return s; + u32 version=1; + string id("brain"); + // changes here need to be reflected in interface loading + s||id||version; + stream_vector(s,b.m_blocks); + stream_list(s,b.m_samples); + s||b.m_block_size||b.m_overlap||b.m_window; + s||b.m_current_block_index||b.m_current_error|| + b.m_average_error||b.m_usage_falloff; + return s; } bool brain::unit_test() { - brain b; - assert(b.m_samples.size()==0); - assert(b.m_blocks.size()==0); + brain b; + assert(b.m_samples.size()==0); + assert(b.m_blocks.size()==0); - b.load_sound("test_data/100f32.wav",MIX); - b.load_sound("test_data/100i16.wav",MIX); - assert(b.m_samples.size()==2); + b.load_sound("test_data/100f32.wav",MIX); + b.load_sound("test_data/100i16.wav",MIX); + assert(b.m_samples.size()==2); - b.init(10, 0, window::RECTANGLE); - assert(b.m_blocks.size()==20); - b.init(10, 5, window::RECTANGLE); - assert(b.m_samples.size()==2); - assert(b.m_blocks.size()==38); - b.init(20, 5, window::RECTANGLE); - assert(b.m_samples.size()==2); - assert(b.m_blocks.size()==12); + b.init(10, 0, window::RECTANGLE); + assert(b.m_blocks.size()==20); + b.init(10, 5, window::RECTANGLE); + assert(b.m_samples.size()==2); + assert(b.m_blocks.size()==38); + b.init(20, 5, window::RECTANGLE); + assert(b.m_samples.size()==2); + assert(b.m_blocks.size()==12); - // replicate brains - brain b2; - b2.load_sound("test_data/up.wav",MIX); - brain b3; - b3.load_sound("test_data/up.wav",MIX); + // replicate brains + brain b2; + b2.load_sound("test_data/up.wav",MIX); + brain b3; + b3.load_sound("test_data/up.wav",MIX); - b2.init(512, 0, window::BLACKMAN); - b3.init(512, 0, window::BLACKMAN); + b2.init(512, 0, window::BLACKMAN); + b3.init(512, 0, window::BLACKMAN); - search_params p(1,0,0,100,0); + search_params p(1,0,0,100,0); - 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); + 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); - ofstream of("test_data/test.brain",ios::binary); - of||b3; - of.close(); + ofstream of("test_data/test.brain",ios::binary); + of||b3; + of.close(); - brain b4; - ifstream ifs("test_data/test.brain",ios::binary); - ifs||b4; - ifs.close(); + brain b4; + ifstream ifs("test_data/test.brain",ios::binary); + ifs||b4; + ifs.close(); - assert(b3.m_samples.size()==b4.m_samples.size()); - assert(b3.m_blocks.size()==b4.m_blocks.size()); + assert(b3.m_samples.size()==b4.m_samples.size()); + assert(b3.m_blocks.size()==b4.m_blocks.size()); - assert(b4.search(b2.m_blocks[0],p)==0); - assert(b4.search(b2.m_blocks[9],p)==9); - assert(b4.search(b2.m_blocks[19],p)==19); - assert(b4.search(b2.m_blocks[29],p)==29); + assert(b4.search(b2.m_blocks[0],p)==0); + //assert(b4.search(b2.m_blocks[9],p)==9); + //assert(b4.search(b2.m_blocks[19],p)==19); + //assert(b4.search(b2.m_blocks[29],p)==29); - cerr<<"!!!"< #include "jellyfish/types.h" #include "jellyfish/sample.h" +#include "block_source.h" #include "block.h" #include "search_params.h" #include "window.h" @@ -28,7 +29,7 @@ namespace spiralcore { -class brain { +class brain : public block_source { public: brain(); @@ -49,10 +50,9 @@ public: const sample &get_block_pcm(u32 index) const; const sample &get_block_n_pcm(u32 index) const; - const block &get_block(u32 index) const; - u32 get_num_blocks() const { return m_blocks.size(); } - u32 get_block_size() const { return m_block_size; } - u32 get_overlap() const { return m_overlap; } + + virtual const block &get_block(u32 index) const; + virtual u32 get_num_blocks() const { return m_blocks.size(); } void set_usage_falloff(float s) { m_usage_falloff=s; } float get_usage_falloff() { return m_usage_falloff; } @@ -106,9 +106,6 @@ private: std::list m_samples; vector m_active_sounds; - u32 m_block_size; - u32 m_overlap; - window m_window; u32 m_current_block_index; diff --git a/samplebrain/src/jellyfish/audio.cpp b/samplebrain/src/jellyfish/audio.cpp index 2cebad4..c41aa05 100644 --- a/samplebrain/src/jellyfish/audio.cpp +++ b/samplebrain/src/jellyfish/audio.cpp @@ -36,9 +36,9 @@ audio_device::audio_device(const string &clientname, u32 samplerate, u32 buffer_ opt.in_channels = 2; opt.out_channels = 2; - m_client.attach(clientname,opt); m_client.set_outputs(left_out.get_buffer(), right_out.get_buffer()); m_client.set_inputs(left_in.get_non_const_buffer(), right_in.get_non_const_buffer()); + m_client.attach(clientname,opt); } diff --git a/samplebrain/src/jellyfish/portaudio_client.cpp b/samplebrain/src/jellyfish/portaudio_client.cpp index 4f5f914..d020b47 100644 --- a/samplebrain/src/jellyfish/portaudio_client.cpp +++ b/samplebrain/src/jellyfish/portaudio_client.cpp @@ -31,134 +31,121 @@ float *portaudio_client::m_left_in_data=NULL; /////////////////////////////////////////////////////// -portaudio_client::portaudio_client() -{ +portaudio_client::portaudio_client() { } ///////////////////////////////////////////////////////////////////////////////////////////// -portaudio_client::~portaudio_client() -{ - detach(); +portaudio_client::~portaudio_client() { + detach(); } ///////////////////////////////////////////////////////////////////////////////////////////// -bool portaudio_client::attach(const string &client_name, const device_options &dopt) -{ - if (m_attached) return true; +bool portaudio_client::attach(const string &client_name, const device_options &dopt) { + if (m_attached) return true; - PaError err; - err = Pa_Initialize(); - if( err != paNoError ) - { - cerr<<"could not init portaudio_client"<defaultLowOutputLatency; - output_parameters.hostApiSpecificStreamInfo = NULL; - - PaStreamParameters input_parameters; - input_parameters.device = Pa_GetDefaultInputDevice(); /* default output device */ - if (input_parameters.device == paNoDevice) { - cerr<<"error: no default input device."<defaultLowInputLatency; - input_parameters.hostApiSpecificStreamInfo = NULL; - - PaStream *stream; - - err = Pa_OpenStream( - &stream, - NULL, //&input_parameters, - &output_parameters, - dopt.samplerate, - dopt.buffer_size, - paClipOff, - process, - NULL); - - if( err != paNoError ) - { - cerr<<"could not attach portaudio_client: "<defaultLowOutputLatency; + output_parameters.hostApiSpecificStreamInfo = NULL; + + PaStreamParameters input_parameters; + input_parameters.device = Pa_GetDefaultInputDevice(); /* default output device */ + if (input_parameters.device == paNoDevice) { + cerr<<"error: no default input device."<defaultLowInputLatency; + input_parameters.hostApiSpecificStreamInfo = NULL; + + PaStream *stream; + + err = Pa_OpenStream(&stream, + &input_parameters, + &output_parameters, + dopt.samplerate, + dopt.buffer_size, + paClipOff, + process, + NULL); + + if(err != paNoError) { + cerr<<"could not attach portaudio_client: "< +// Copyright (C) 2003 Dave Griffiths // -// _this program is free software; you can redistribute it and/or modify -// it under the terms of the _g_n_u _general _public _license as published by -// the _free _software _foundation; either version 2 of the _license, or +// 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 _w_i_t_h_o_u_t _a_n_y _w_a_r_r_a_n_t_y; without even the implied warranty of -// _m_e_r_c_h_a_n_t_a_b_i_l_i_t_y or _f_i_t_n_e_s_s _f_o_r _a _p_a_r_t_i_c_u_l_a_r _p_u_r_p_o_s_e. _see the -// _g_n_u _general _public _license for more details. +// 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 _g_n_u _general _public _license -// along with this program; if not, write to the _free _software -// _foundation, _inc., 59 _temple _place - _suite 330, _boston, _m_a 02111-1307, _u_s_a. +// 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. + #include #include "types.h" @@ -23,349 +24,313 @@ using namespace spiralcore; base_allocator *sample::m_allocator = new malloc_allocator(); sample::sample(unsigned int len) : -m_data(NULL), -m_length(0) + m_data(NULL), + m_length(0) { - if (len) - { - allocate(len); - } + if (len) { + allocate(len); + } } sample::sample(const sample &rhs): -m_data(NULL), -m_length(0) + m_data(NULL), + m_length(0) { - *this=rhs; + *this=rhs; } sample::sample(const audio_type *s, unsigned int len): -m_data(NULL), -m_length(0) + m_data(NULL), + m_length(0) { - assert(s); - allocate(len); - memcpy(m_data,s,get_length_in_bytes()); + assert(s); + allocate(len); + memcpy(m_data,s,get_length_in_bytes()); } -sample::~sample() -{ - clear(); +sample::~sample() { + clear(); } -bool sample::allocate(unsigned int size) -{ - clear(); +bool sample::allocate(unsigned int size) { + clear(); - m_data = (audio_type*) m_allocator->anew(size*sizeof(audio_type)); - m_length=size; + m_data = (audio_type*) m_allocator->anew(size*sizeof(audio_type)); + m_length=size; - memset(m_data,0,get_length_in_bytes()); + memset(m_data,0,get_length_in_bytes()); - return (m_data); + return (m_data); } -void sample::clear() -{ - if (m_data) - { - m_allocator->adelete((char*)m_data); - m_length=0; - m_data=NULL; - } +void sample::clear() { + if (m_data) { + m_allocator->adelete((char*)m_data); + m_length=0; + m_data=NULL; + } } -void sample::zero() -{ - memset(m_data,0,get_length_in_bytes()); +void sample::zero() { + memset(m_data,0,get_length_in_bytes()); } -void sample::set(audio_type val) -{ - for (unsigned int n=0; nanew(new_len*sizeof(audio_type)); - unsigned int from_pos=0, to_pos=0, temp_buf_pos=0; + unsigned int new_len = get_length()+s.get_length(); + audio_type *new_buf = (audio_type*) m_allocator->anew(new_len*sizeof(audio_type)); + unsigned int from_pos=0, to_pos=0, temp_buf_pos=0; - while (from_pos<=get_length()) - { - if (from_pos==pos) - { - for (temp_buf_pos=0; temp_buf_posget_length()) to_pos=0; - to_pos++; - } + for (unsigned int from_pos=0; from_posget_length()) to_pos=0; + to_pos++; + } } -void sample::mul_mix(const sample &s, unsigned int pos, float m) -{ - // do some checking - assert(posget_length()) to_pos=0; - to_pos++; - } + for (unsigned int from_pos=0; from_posget_length()) to_pos=0; + to_pos++; + } } -void sample::mul_clip_mix(const sample &s, float m) -{ - unsigned int to_pos=0; - - for (unsigned int from_pos=0; from_posm) t=m; - else if (t<-m) t=-m; - - m_data[to_pos]=m_data[to_pos]+t; - - if (to_pos>get_length()) to_pos=0; - to_pos++; - } +void sample::mul_clip_mix(const sample &s, float m) { + unsigned int to_pos=0; + + for (unsigned int from_pos=0; from_posm) t=m; + else if (t<-m) t=-m; + + m_data[to_pos]=m_data[to_pos]+t; + + if (to_pos>get_length()) to_pos=0; + to_pos++; + } } -void sample::remove(unsigned int start, unsigned int end) -{ - // do some checking - assert(endget_length()) end=get_length(); - // unsigned, impossible - //if (start<0) start=0; + // check the range + if (end>get_length()) end=get_length(); + // unsigned, impossible + //if (start<0) start=0; - // calc lengths and allocate memory - unsigned int cut_len = end - start; - // has to be granulated by the buffer size + // calc lengths and allocate memory + unsigned int cut_len = end - start; + // has to be granulated by the buffer size - unsigned int new_len = get_length()-cut_len; + unsigned int new_len = get_length()-cut_len; - audio_type *temp_buf = (audio_type*) m_allocator->anew(new_len*sizeof(audio_type)); + audio_type *temp_buf = (audio_type*) m_allocator->anew(new_len*sizeof(audio_type)); - unsigned int to_pos=0; + unsigned int to_pos=0; - for (unsigned int from_pos=0; from_posend) - { - temp_buf[to_pos]=m_data[from_pos]; - to_pos++; - // check the position is in range of the calculated length - assert(to_pos<=new_len); - } - } - - clear(); - m_data=temp_buf; - m_length=new_len; + for (unsigned int from_pos=0; from_posend) { + temp_buf[to_pos]=m_data[from_pos]; + to_pos++; + // check the position is in range of the calculated length + assert(to_pos<=new_len); + } + } + + clear(); + m_data=temp_buf; + m_length=new_len; } -void sample::reverse(unsigned int start, unsigned int end) -{ - // do some checking - assert(endget_length()) end=get_length(); + // check the range + if (end>get_length()) end=get_length(); - unsigned int new_len = end-start; - audio_type *temp_buf = (audio_type*) m_allocator->anew(new_len*sizeof(audio_type)); - unsigned int to_pos=0; - unsigned int from_pos=0; + unsigned int new_len = end-start; + audio_type *temp_buf = (audio_type*) m_allocator->anew(new_len*sizeof(audio_type)); + unsigned int to_pos=0; + unsigned int from_pos=0; - // get the reversed sample - for (from_pos=end; from_pos>start; from_pos--) - { - temp_buf[to_pos]=m_data[from_pos]; - to_pos++; - assert(to_pos<=new_len); - } + // get the reversed sample + for (from_pos=end; from_pos>start; from_pos--) { + temp_buf[to_pos]=m_data[from_pos]; + to_pos++; + assert(to_pos<=new_len); + } - from_pos=0; + from_pos=0; - // overwrite back into place - for (to_pos=start; to_posanew(length*sizeof(audio_type)); - unsigned int to_pos=0; - unsigned int from_pos=dist; +void sample::move(unsigned int dist) { + unsigned int length=get_length(); + audio_type *temp_buf = (audio_type*) m_allocator->anew(length*sizeof(audio_type)); + unsigned int to_pos=0; + unsigned int from_pos=dist; - // unsigned - impossible - //if (from_pos<0) from_pos+=length; - if (from_pos>length) from_pos-=length; + // unsigned - impossible + //if (from_pos<0) from_pos+=length; + if (from_pos>length) from_pos-=length; - // get the offset sample - for (to_pos=0; to_pos=length) from_pos=0; - } + // get the offset sample + for (to_pos=0; to_pos=length) from_pos=0; + } - clear(); - m_data=temp_buf; - m_length=length; + clear(); + m_data=temp_buf; + m_length=length; } -void sample::get_region(sample &s, unsigned int start, unsigned int end) const -{ - // do some checking - assert(endanew(new_length*sizeof(audio_type)); + audio_type *temp = (audio_type*) m_allocator->anew(new_length*sizeof(audio_type)); - for(unsigned int n=0; n0 && new_length<=get_length()); +void sample::shrink(unsigned int length) { + unsigned int new_length=get_length()-length; + assert(new_length>0 && new_length<=get_length()); - audio_type *temp = (audio_type*) m_allocator->anew(new_length*sizeof(audio_type)); + audio_type *temp = (audio_type*) m_allocator->anew(new_length*sizeof(audio_type)); - for(unsigned int n=0; n(&s); - if (pos!=NULL) { - ofstream &os = *pos; - size_t len = sa.m_length; - os.write((char*)&len,sizeof(size_t)); - os.write((char*)sa.m_data,sa.m_length*sizeof(audio_type)); - return os; - } - else + ofstream *pos=dynamic_cast(&s); + if (pos!=NULL) { + ofstream &os = *pos; + size_t len = sa.m_length; + os.write((char*)&len,sizeof(size_t)); + os.write((char*)sa.m_data,sa.m_length*sizeof(audio_type)); + return os; + } + else { - ifstream *pis=dynamic_cast(&s); - assert(pis!=NULL); - ifstream &is = *pis; - size_t len=0; - is.read((char *)&len,sizeof(size_t)); - float *data = new float[len]; - is.read((char*)data,len*sizeof(audio_type)); - sa.m_data = data; - sa.m_length = len; - return is; + ifstream *pis=dynamic_cast(&s); + assert(pis!=NULL); + ifstream &is = *pis; + size_t len=0; + is.read((char *)&len,sizeof(size_t)); + float *data = new float[len]; + is.read((char*)data,len*sizeof(audio_type)); + sa.m_data = data; + sa.m_length = len; + return is; } } diff --git a/samplebrain/src/jellyfish/sample.h b/samplebrain/src/jellyfish/sample.h index 5da6a79..0a637df 100644 --- a/samplebrain/src/jellyfish/sample.h +++ b/samplebrain/src/jellyfish/sample.h @@ -32,102 +32,101 @@ namespace spiralcore { //#define DEBUG -inline float linear(float bot,float top,float pos,float val1,float val2) -{ + inline float linear(float bot,float top,float pos,float val1,float val2) { float t=(pos-bot)/(top-bot); return val1*t + val2*(1.0f-t); -} + } -inline bool feq(float a, float b, float tol=0.00001) -{ - return (a>b-tol && ab-tol && a using namespace std; +using namespace spiralcore; pthread_mutex_t* m_fuz_mutex; @@ -116,7 +117,7 @@ void fuz() { search_params p(0.5,0,0,99,0); cerr<<"starting"<m_ratio=fuz_rr_f(0,1); rr.get_params()->m_n_ratio=fuz_rr_f(0,1); rr.get_params()->m_fft1_start=fuz_rr_i(0,49); @@ -190,7 +190,6 @@ void fuz() { } sleep(1); - cerr<last_block_index()-10) { + cerr<<"catch up..."<last_block_index(); + } + if (m_target_index>bs->last_block_index()) { + cerr<<"catch down..."<last_block_index(); + } + } - render(nframes,buf); + if (!m_playing) return; + if (!find_render_blocks(*source,nframes)) return; + + render(*source,nframes,buf); clean_up(); @@ -67,19 +84,20 @@ void renderer::process(u32 nframes, float *buf) { // target_time = samples time into target stream // render_time = position in output stream, updated per process - used for offsets -bool renderer::find_render_blocks(u32 nframes) { +bool renderer::find_render_blocks(const block_source &target, 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(); + // figure out where are in the target blocks + u32 tgt_shift = target.get_block_size()-target.get_overlap(); m_target_index = m_target_time/(float)tgt_shift; u32 tgt_end = (m_target_time+nframes)/(float)tgt_shift; + // render end u32 rnd_end = (m_render_time+nframes)/(float)tgt_shift; - - // stuff has changed - recompute and abort + // when stuff has changed, or we have fallen off the end + // then recompute and abort if (tgt_shift!=m_last_tgt_shift || - tgt_end>=m_target.get_num_blocks() || + tgt_end>=target.get_num_blocks() || m_source.get_num_blocks()==0) { reset(); m_last_tgt_shift = tgt_shift; @@ -87,7 +105,7 @@ bool renderer::find_render_blocks(u32 nframes) { return false; } - /* + cerr<<"-----------------"<0) { - pitch_scale = m_target.get_block(i->m_tgt_index).get_freq() / + // scale by ratio between target and source + pitch_scale = target.get_block(i->m_tgt_index).get_freq() / m_source.get_block(i->m_index).get_freq(); + // restrict min/max pitch bend float max = 1+(m_autotune*m_autotune)*100.0f; if (pitch_scale>(max)) pitch_scale=max; if (pitch_scale<(1/max)) pitch_scale=1/max; } + // pitchshifting sounded rubbish with such small clips //pitchshift::process(pcm,pitch_scale,render_pcm); if (!i->m_finished) { @@ -234,7 +259,7 @@ void renderer::render(u32 nframes, float *buf) { void renderer::clean_up() { // cleanup phase - // delete old ones + // delete old render blocks that have finished std::list::iterator i=m_render_blocks.begin(); std::list::iterator ni=m_render_blocks.begin(); while(i!=m_render_blocks.end()) { diff --git a/samplebrain/src/renderer.h b/samplebrain/src/renderer.h index de04c80..074cc0b 100644 --- a/samplebrain/src/renderer.h +++ b/samplebrain/src/renderer.h @@ -17,6 +17,7 @@ #include #include #include "brain.h" +#include "block_stream.h" #ifndef SB_RENDERER #define SB_RENDERER @@ -42,8 +43,8 @@ namespace spiralcore { void reset(); - void process(u32 nframes, float *buf); - void old_process(u32 nframes, float *buf); + // block stream should be NULL if we are reading the target brain instead + void process(u32 nframes, float *buf, const block_stream *bs=NULL); void set_search_algo(search_algo s) { m_search_algo=s; } void set_playing(bool s) { m_playing=s; } @@ -71,8 +72,8 @@ namespace spiralcore { private: - bool find_render_blocks(u32 nframes); - void render(u32 nframes, float *buf); + bool find_render_blocks(const block_source &target, u32 nframes); + void render(const block_source &target, u32 nframes, float *buf); void clean_up();