mirror of
https://gitlab.com/then-try-this/samplebrain.git
synced 2026-06-28 09:31:38 +00:00
big directory re-org
This commit is contained in:
186
app/MainWindow.cpp
Normal file
186
app/MainWindow.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
// Copyright (C) 2015 Dave Griffiths
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <QtGui>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "feedback.h"
|
||||
#include "renderer.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
MainWindow::MainWindow() :
|
||||
m_last_file("."),
|
||||
m_feedback("8890")
|
||||
{
|
||||
m_sound_item_enable_mapper = new QSignalMapper(this);
|
||||
m_sound_item_delete_mapper = new QSignalMapper(this);
|
||||
|
||||
connect(m_sound_item_enable_mapper,
|
||||
SIGNAL(mapped(int)), this, SLOT(sound_enable(int)));
|
||||
connect(m_sound_item_delete_mapper,
|
||||
SIGNAL(mapped(int)), this, SLOT(delete_sound(int)));
|
||||
|
||||
m_Ui.setupUi(this);
|
||||
setUnifiedTitleAndToolBarOnMac(true);
|
||||
|
||||
m_Ui.verticalLayout_5->setSpacing(0);
|
||||
m_Ui.verticalLayout_5->setMargin(0);
|
||||
m_Ui.verticalLayout_5->setContentsMargins(0,0,0,0);
|
||||
|
||||
m_Ui.brain_contents->setAlignment(Qt::AlignTop);
|
||||
m_Ui.brain_contents->setSpacing(0);
|
||||
m_Ui.brain_contents->setMargin(0);
|
||||
m_Ui.brain_contents->setContentsMargins(0,0,0,0);
|
||||
|
||||
// add default local dest
|
||||
// turn on first one
|
||||
|
||||
QSignalMapper* enable_mapper = new QSignalMapper(this);
|
||||
|
||||
for (int i=0; i<10; i++) {
|
||||
osc_destination d;
|
||||
d.m_id=i;
|
||||
d.m_audio_address = lo_address_new_from_url("osc.udp://localhost:8888");
|
||||
d.m_process_address = lo_address_new_from_url("osc.udp://localhost:8889");
|
||||
if (i==0) d.m_enabled=true;
|
||||
else d.m_enabled=false;
|
||||
add_gui_address(d,enable_mapper);
|
||||
|
||||
if (i==0) {
|
||||
d.m_enable->setChecked(true);
|
||||
d.m_address->setText("osc.udp://localhost");
|
||||
}
|
||||
m_destinations.push_back(d);
|
||||
}
|
||||
|
||||
connect(enable_mapper, SIGNAL(mapped(int)), this, SLOT(net_enable(int)));
|
||||
|
||||
m_Ui.netContainer->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(update_status()));
|
||||
timer->start(1000);
|
||||
timer->setInterval(500);
|
||||
|
||||
m_save_wav="";
|
||||
m_record_id=0;
|
||||
}
|
||||
|
||||
void MainWindow::add_gui_address(osc_destination &dest,
|
||||
QSignalMapper* enable_mapper) {
|
||||
QHBoxLayout *h = new QHBoxLayout();
|
||||
dest.m_enable = new QCheckBox();
|
||||
dest.m_enable->setText("enable");
|
||||
dest.m_enable->setChecked(false);
|
||||
h->addWidget(dest.m_enable);
|
||||
dest.m_address = new QLineEdit();
|
||||
h->addWidget(dest.m_address);
|
||||
m_Ui.netContainer->addLayout(h);
|
||||
|
||||
QObject::connect(dest.m_enable, SIGNAL(clicked()), enable_mapper, SLOT(map()));
|
||||
enable_mapper->setMapping(dest.m_enable, dest.m_id);
|
||||
}
|
||||
|
||||
void MainWindow::init_from_session(const string &filename) {
|
||||
// pull the bits out of the file to set the interface...
|
||||
// is this easier than direct access? no idea??
|
||||
ifstream ifs(filename.c_str(),ios::binary);
|
||||
|
||||
brain s,t;
|
||||
u32 version=0;
|
||||
ifs||version;
|
||||
renderer r(s,t);
|
||||
ifs||r;
|
||||
ifs||r;
|
||||
|
||||
u32 target_windowsize;
|
||||
u32 source_windowsize;
|
||||
window::type target_window;
|
||||
window::type source_window;
|
||||
float target_overlap;
|
||||
float source_overlap;
|
||||
int t_int;
|
||||
// skip this...
|
||||
ifs||source_windowsize||source_overlap;
|
||||
ifs||target_windowsize||target_overlap;
|
||||
ifs||source_window||target_window;
|
||||
// todo: probably don't need to load all the sample data too :/
|
||||
ifs||s;
|
||||
ifs||t;
|
||||
|
||||
// brain tweaks
|
||||
search_params * p = r.get_params();
|
||||
|
||||
m_Ui.sliderRatio->setValue(p->m_ratio*100);
|
||||
m_Ui.doubleSpinBoxRatio->setValue(p->m_ratio);
|
||||
m_Ui.sliderNRatio->setValue(p->m_n_ratio*100);
|
||||
m_Ui.doubleSpinBoxNRatio->setValue(p->m_n_ratio);
|
||||
m_Ui.spinBoxFFT1Start->setValue(p->m_fft1_start);
|
||||
m_Ui.spinBoxFFT1End->setValue(p->m_fft1_end);
|
||||
m_Ui.sliderNovelty->setValue(p->m_usage_importance*100);
|
||||
m_Ui.doubleSpinBoxNovelty->setValue(p->m_usage_importance);
|
||||
m_Ui.sliderBoredom->setValue(s.get_usage_falloff()*100);
|
||||
m_Ui.doubleSpinBoxBoredom->setValue(s.get_usage_falloff());
|
||||
m_Ui.sliderStickyness->setValue(p->m_stickyness*100);
|
||||
m_Ui.doubleSpinBoxStickyness->setValue(p->m_stickyness);
|
||||
m_Ui.sliderSearchStretch->setValue(r.get_stretch());
|
||||
m_Ui.spinBoxSearchStretch->setValue(r.get_stretch());
|
||||
|
||||
m_Ui.comboBoxAlgorithm->setCurrentIndex(r.get_search_algo());
|
||||
|
||||
m_Ui.sliderSynapses->setValue(p->m_num_synapses);
|
||||
m_Ui.spinBoxSynapses->setValue(p->m_num_synapses);
|
||||
m_Ui.sliderSlideError->setValue(r.get_slide_error());
|
||||
m_Ui.spinBoxSlideError->setValue(r.get_slide_error());
|
||||
|
||||
// target
|
||||
m_Ui.spinBoxBlockSizeTarget->setValue(t.get_block_size());
|
||||
m_Ui.doubleSpinBoxBlockOverlapTarget->setValue(t.get_overlap()/(float)t.get_block_size());
|
||||
|
||||
m_Ui.comboBoxTargetShape->setCurrentIndex(target_window);
|
||||
|
||||
// source
|
||||
m_Ui.spinBoxBlockSize->setValue(s.get_block_size());
|
||||
m_Ui.doubleSpinBoxBlockOverlap->setValue(s.get_overlap()/(float)s.get_block_size());
|
||||
m_Ui.comboBoxBrainShape->setCurrentIndex(source_window);
|
||||
|
||||
// brain samples
|
||||
m_sound_items.clear();
|
||||
for (auto &i:s.get_samples()) {
|
||||
sound_items::sound_item &si = m_sound_items.add(m_Ui.brain_contents,i.m_filename,i.m_enabled);
|
||||
|
||||
QObject::connect(si.m_enable, SIGNAL(clicked()), m_sound_item_enable_mapper, SLOT(map()));
|
||||
m_sound_item_enable_mapper->setMapping(si.m_enable, si.m_id);
|
||||
QObject::connect(si.m_del, SIGNAL(clicked()), m_sound_item_delete_mapper, SLOT(map()));
|
||||
m_sound_item_delete_mapper->setMapping(si.m_del, si.m_id);
|
||||
}
|
||||
// todo: might contain unprocessed samples in colour scheme
|
||||
m_sound_items.recolour();
|
||||
|
||||
// mix
|
||||
m_Ui.sliderTargetMix->setValue(r.get_target_mix()*100);
|
||||
m_Ui.doubleSpinBoxTargetMix->setValue(r.get_target_mix());
|
||||
m_Ui.sliderNMix->setValue(r.get_n_mix()*100);
|
||||
m_Ui.doubleSpinBoxNMix->setValue(r.get_n_mix());
|
||||
m_Ui.sliderAutotune->setValue(r.get_autotune()*100);
|
||||
m_Ui.doubleSpinBoxAutotune->setValue(r.get_autotune());
|
||||
|
||||
|
||||
|
||||
}
|
||||
415
app/MainWindow.h
Normal file
415
app/MainWindow.h
Normal file
@@ -0,0 +1,415 @@
|
||||
// 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.
|
||||
|
||||
#include <QtGui>
|
||||
#include <QDirIterator>
|
||||
#include <QFileDialog>
|
||||
#include <QLineEdit>
|
||||
#include "generated/ui_samplebrain.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <lo/lo.h>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include "feedback.h"
|
||||
#include "sound_items.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace spiralcore;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow();
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
private slots:
|
||||
|
||||
void play_slot() { send_audio_osc("/start",""); }
|
||||
void stop_slot() { send_audio_osc("/pause",""); }
|
||||
|
||||
void ratio_slot(int s) {
|
||||
send_audio_osc("/ratio","f",s/100.0f);
|
||||
m_Ui.doubleSpinBoxRatio->setValue(s/100.0f);
|
||||
}
|
||||
void ratio_slot(double s) {
|
||||
send_audio_osc("/ratio","f",s);
|
||||
m_Ui.sliderRatio->setValue(s*100);
|
||||
}
|
||||
|
||||
void n_ratio_slot(int s) {
|
||||
send_audio_osc("/n_ratio","f",s/100.0f);
|
||||
m_Ui.doubleSpinBoxNRatio->setValue(s/100.0f);
|
||||
}
|
||||
void n_ratio_slot(double s) {
|
||||
send_audio_osc("/n_ratio","f",s);
|
||||
m_Ui.sliderNRatio->setValue(s*100);
|
||||
}
|
||||
|
||||
void autotune(int s) {
|
||||
send_audio_osc("/autotune","f",s/100.0f);
|
||||
m_Ui.doubleSpinBoxAutotune->setValue(s/100.0f);
|
||||
}
|
||||
void autotune(double s) {
|
||||
send_audio_osc("/autotune","f",s);
|
||||
m_Ui.sliderAutotune->setValue(s*100);
|
||||
}
|
||||
|
||||
void fft1_start_slot(int s) { send_audio_osc("/fft1_start","i",s); }
|
||||
void fft1_end_slot(int s) { send_audio_osc("/fft1_end","i",s); }
|
||||
void fft2_start_slot(int s){} // { m_renderer->get_params()->m_fft2_start=s; }
|
||||
void fft2_end_slot(int s){} // { m_renderer->get_params()->m_fft2_end=s; }
|
||||
|
||||
void n_mix_slot(int s) {
|
||||
send_audio_osc("/n_mix","f",s/100.0f);
|
||||
m_Ui.doubleSpinBoxNMix->setValue(s/100.0f);
|
||||
}
|
||||
void n_mix_slot(double s) {
|
||||
send_audio_osc("/n_mix","f",s);
|
||||
m_Ui.sliderNMix->setValue(s*100);
|
||||
}
|
||||
|
||||
void novelty_slot(int s) {
|
||||
send_audio_osc("/novelty","f",s/100.0f);
|
||||
m_Ui.doubleSpinBoxNovelty->setValue(s/100.0f);
|
||||
}
|
||||
void novelty_slot(double s) {
|
||||
send_audio_osc("/novelty","f",s);
|
||||
m_Ui.sliderNovelty->setValue(s*100);
|
||||
}
|
||||
|
||||
void boredom_slot(int s) {
|
||||
float v=s/100.0f;
|
||||
send_audio_osc("/boredom","f",v);
|
||||
m_Ui.doubleSpinBoxBoredom->setValue(v);
|
||||
}
|
||||
void boredom_slot(double s) {
|
||||
send_audio_osc("/boredom","f",s);
|
||||
m_Ui.sliderBoredom->setValue(s*100);
|
||||
}
|
||||
void synapses(int s) {
|
||||
send_audio_osc("/synapses","i",s);
|
||||
}
|
||||
void target_mix_slot(int s) {
|
||||
send_audio_osc("/target_mix","f",s/100.0f);
|
||||
m_Ui.doubleSpinBoxTargetMix->setValue(s/100.0f);
|
||||
}
|
||||
void target_mix_slot(double s) {
|
||||
send_audio_osc("/target_mix","f",s);
|
||||
m_Ui.sliderTargetMix->setValue(s*100);
|
||||
}
|
||||
void search_stretch(int s) {
|
||||
send_audio_osc("/search-stretch","i",s);
|
||||
}
|
||||
void slide_error(int s) {
|
||||
send_audio_osc("/slide-error","i",s);
|
||||
}
|
||||
void stickyness_slot(int s) {
|
||||
send_audio_osc("/stickyness","f",s/100.0f);
|
||||
m_Ui.doubleSpinBoxStickyness->setValue(s/100.0f);
|
||||
}
|
||||
void stickyness_slot(double s) {
|
||||
send_audio_osc("/stickyness","f",s);
|
||||
m_Ui.sliderStickyness->setValue(s*100);
|
||||
}
|
||||
|
||||
void volume_slot(int s) { send_audio_osc("/volume","f",s/100.0f); }
|
||||
void algo(int n) { send_audio_osc("/search_algo","i",n); }
|
||||
|
||||
void run_slot() {}
|
||||
void load_target() {
|
||||
m_last_file=QFileDialog::getOpenFileName(
|
||||
this,
|
||||
QString("Select an wav file"),
|
||||
m_last_file,
|
||||
QString("Sounds (*.wav)"));
|
||||
|
||||
send_process_osc("/load_target","s",m_last_file.toStdString().c_str());
|
||||
}
|
||||
void target_block_size(int s) { send_process_osc("/target_block_size","i",s); }
|
||||
void target_block_overlap(double s) { send_process_osc("/target_overlap","f",s); }
|
||||
void generate_target_blocks() { send_process_osc("/generate_target",""); }
|
||||
void block_size(int s) { send_process_osc("/source_block_size","i",s); }
|
||||
void block_overlap(double s) { send_process_osc("/source_overlap","f",s); }
|
||||
void fft_spectrum_size(int) {}
|
||||
void generate() { send_process_osc("/generate_brain",""); }
|
||||
void load_sound() {
|
||||
m_last_file=QFileDialog::getOpenFileName(
|
||||
this,
|
||||
QString("Select a wav file"),
|
||||
m_last_file,
|
||||
QString("Sounds (*.wav)"));
|
||||
|
||||
send_process_osc("/load_sample","s",m_last_file.toStdString().c_str());
|
||||
|
||||
sound_items::sound_item &si = m_sound_items.add(m_Ui.brain_contents, m_last_file.toStdString(),true);
|
||||
|
||||
QObject::connect(si.m_enable, SIGNAL(clicked()), m_sound_item_enable_mapper, SLOT(map()));
|
||||
m_sound_item_enable_mapper->setMapping(si.m_enable, si.m_id);
|
||||
QObject::connect(si.m_del, SIGNAL(clicked()), m_sound_item_delete_mapper, SLOT(map()));
|
||||
m_sound_item_delete_mapper->setMapping(si.m_del, si.m_id);
|
||||
}
|
||||
|
||||
|
||||
void load_sounds() {
|
||||
m_last_file=QFileDialog::getExistingDirectory(this,
|
||||
QString("Select a directory"),
|
||||
m_last_file);
|
||||
|
||||
|
||||
QDirIterator dirIt(m_last_file,QDirIterator::Subdirectories);
|
||||
while (dirIt.hasNext()) {
|
||||
dirIt.next();
|
||||
if (QFileInfo(dirIt.filePath()).isFile() &&
|
||||
QFileInfo(dirIt.filePath()).suffix() == "wav") {
|
||||
send_process_osc("/load_sample","s",dirIt.filePath().toStdString().c_str());
|
||||
|
||||
sound_items::sound_item &si = m_sound_items.add(m_Ui.brain_contents, dirIt.filePath().toStdString(),true);
|
||||
|
||||
QObject::connect(si.m_enable, SIGNAL(clicked()), m_sound_item_enable_mapper, SLOT(map()));
|
||||
m_sound_item_enable_mapper->setMapping(si.m_enable, si.m_id);
|
||||
QObject::connect(si.m_del, SIGNAL(clicked()), m_sound_item_delete_mapper, SLOT(map()));
|
||||
m_sound_item_delete_mapper->setMapping(si.m_del, si.m_id);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void select_all() {
|
||||
for (auto &si:m_sound_items.m_sound_items) {
|
||||
si.m_enable->setChecked(true);
|
||||
send_process_osc("/activate_sound","s",si.m_filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void select_none() {
|
||||
for (auto &si:m_sound_items.m_sound_items) {
|
||||
si.m_enable->setChecked(false);
|
||||
send_process_osc("/deactivate_sound","s",si.m_filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void sound_enable(int id) {
|
||||
// search for this id...
|
||||
for (auto &si:m_sound_items.m_sound_items) {
|
||||
if (si.m_id==id) {
|
||||
if (si.m_enable->isChecked()) {
|
||||
send_process_osc("/activate_sound","s",si.m_filename.c_str());
|
||||
} else {
|
||||
send_process_osc("/deactivate_sound","s",si.m_filename.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void delete_sound(int id) {
|
||||
// search for this id...
|
||||
for (auto &si:m_sound_items.m_sound_items) {
|
||||
if (si.m_id==id) {
|
||||
send_process_osc("/delete_sample","s",si.m_filename.c_str());
|
||||
m_sound_items.remove(si.m_filename);
|
||||
// iterator is now invalidated...
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
void clear_brain() {
|
||||
for (auto &si:m_sound_items.m_sound_items) {
|
||||
send_process_osc("/delete_sample","s",si.m_filename.c_str());
|
||||
}
|
||||
m_sound_items.clear();
|
||||
}
|
||||
void restart_audio() { send_audio_osc("/restart_audio",""); }
|
||||
|
||||
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=="") {
|
||||
m_last_file=QFileDialog::getSaveFileName(
|
||||
this,
|
||||
QString("Select a wav file"),
|
||||
m_last_file,
|
||||
QString("Sounds (*.wav)"));
|
||||
m_save_wav = m_last_file.toStdString();
|
||||
// chop off .wav
|
||||
size_t pos = m_save_wav.find_last_of(".");
|
||||
if (pos!=string::npos) {
|
||||
m_save_wav = m_save_wav.substr(0,pos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
char fn[1024];
|
||||
snprintf(fn,1024,"%s-%i",m_save_wav.c_str(),m_record_id);
|
||||
send_audio_osc("/record","s",fn);
|
||||
cerr<<fn<<endl;
|
||||
m_record_id++;
|
||||
}
|
||||
|
||||
void stop_record() {
|
||||
send_audio_osc("/stop","");
|
||||
}
|
||||
|
||||
void load_brain() {
|
||||
m_last_file=QFileDialog::getOpenFileName(
|
||||
this,
|
||||
QString("Select a brain file"),
|
||||
m_last_file,
|
||||
QString("Brains (*.brain)"));
|
||||
|
||||
send_process_osc("/load_brain","s",m_last_file.toStdString().c_str());
|
||||
}
|
||||
void save_brain() {
|
||||
m_last_file=QFileDialog::getSaveFileName(
|
||||
this,
|
||||
QString("Select a brain file"),
|
||||
m_last_file,
|
||||
QString("Brains (*.brain)"));
|
||||
|
||||
send_process_osc("/save_brain","s",m_last_file.toStdString().c_str());
|
||||
}
|
||||
|
||||
void load_session() {
|
||||
m_last_file=QFileDialog::getOpenFileName(
|
||||
this,
|
||||
QString("Select a session file"),
|
||||
m_last_file,
|
||||
QString("Sessions *.samplebrain (*.samplebrain)"));
|
||||
|
||||
send_process_osc("/load_session","s",m_last_file.toStdString().c_str());
|
||||
init_from_session(m_last_file.toStdString());
|
||||
}
|
||||
|
||||
void save_session() {
|
||||
m_last_file=QFileDialog::getSaveFileName(
|
||||
this,
|
||||
QString("Select a session file"),
|
||||
m_last_file,
|
||||
QString("Sessions *.samplebrain (*.samplebrain)"));
|
||||
|
||||
send_process_osc("/save_session","s",m_last_file.toStdString().c_str());
|
||||
}
|
||||
|
||||
void update_status() {
|
||||
m_feedback.poll(m_Ui.statusbar,&m_sound_items);
|
||||
}
|
||||
|
||||
void stereo_mode(bool s) {
|
||||
send_audio_osc("/stereo","i",s);
|
||||
}
|
||||
|
||||
void net_enable(int id) {
|
||||
osc_destination &d = m_destinations[id];
|
||||
|
||||
if (d.m_enable->isChecked()) {
|
||||
// reconnect
|
||||
string url = d.m_address->text().toUtf8().constData();
|
||||
lo_address_free(d.m_audio_address);
|
||||
lo_address_free(d.m_process_address);
|
||||
d.m_audio_address = lo_address_new_from_url(string(url+":8888").c_str());
|
||||
d.m_process_address = lo_address_new_from_url(string(url+":8889").c_str());
|
||||
// start sending messages here
|
||||
d.m_enabled=true;
|
||||
} else {
|
||||
// stop sending messages here
|
||||
d.m_enabled=false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
///////////////////////////////////////////////
|
||||
|
||||
// we want to be able to send out to
|
||||
// multiple addresses over the network
|
||||
|
||||
////////////////////////////////////////////////
|
||||
|
||||
|
||||
// we want to be able to send out to
|
||||
// multiple addresses over the network
|
||||
class osc_destination {
|
||||
public:
|
||||
int m_id;
|
||||
lo_address m_audio_address;
|
||||
lo_address m_process_address;
|
||||
// can't find a way to address these via qt
|
||||
QLineEdit *m_address;
|
||||
QCheckBox *m_enable;
|
||||
bool m_enabled;
|
||||
};
|
||||
|
||||
vector<osc_destination> m_destinations;
|
||||
|
||||
// all this to work around liblo's use of varargs...
|
||||
void send_audio_osc(const char *name, const char *types) {
|
||||
for (auto dest:m_destinations) {
|
||||
if (dest.m_enabled) {
|
||||
lo_send(dest.m_audio_address,name,types);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void send_audio_osc(const char *name, const char *types, T val) {
|
||||
for (auto dest:m_destinations) {
|
||||
if (dest.m_enabled) {
|
||||
lo_send(dest.m_audio_address,name,types,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void send_process_osc(const char *name, const char *types) {
|
||||
for (auto dest:m_destinations) {
|
||||
if (dest.m_enabled) {
|
||||
lo_send(dest.m_process_address,name,types);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void send_process_osc(const char *name, const char *types, T val) {
|
||||
for (auto dest:m_destinations) {
|
||||
if (dest.m_enabled) {
|
||||
lo_send(dest.m_process_address,name,types,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void init_from_session(const string &filename);
|
||||
void add_gui_address(osc_destination &dest,
|
||||
QSignalMapper* enable_mapper);
|
||||
|
||||
string m_save_wav;
|
||||
QString m_last_file;
|
||||
unsigned int m_record_id;
|
||||
Ui_MainWindow m_Ui;
|
||||
feedback m_feedback;
|
||||
QSignalMapper* m_sound_item_enable_mapper;
|
||||
QSignalMapper* m_sound_item_delete_mapper;
|
||||
sound_items m_sound_items;
|
||||
|
||||
|
||||
};
|
||||
200
app/audio_thread.cpp
Normal file
200
app/audio_thread.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
// 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.
|
||||
|
||||
#include "audio_thread.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace spiralcore;
|
||||
using namespace std;
|
||||
|
||||
audio_thread::audio_thread(process_thread &p) :
|
||||
m_audio_device(NULL),
|
||||
m_osc("8888"),
|
||||
m_process_thread(p),
|
||||
m_brain_mutex(p.m_brain_mutex),
|
||||
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();
|
||||
}
|
||||
|
||||
static bool state = 1;
|
||||
|
||||
audio_thread::~audio_thread() {
|
||||
state=0;
|
||||
if (m_audio_device!=NULL) delete m_audio_device;
|
||||
delete m_left_renderer;
|
||||
delete m_right_renderer;
|
||||
}
|
||||
|
||||
void audio_thread::start_audio() {
|
||||
if (m_audio_device!=NULL) delete m_audio_device;
|
||||
m_audio_device = new audio_device("samplebrain",48000,2048);
|
||||
//m_audio_device = new audio_device("samplebrain",48000,2048*4);
|
||||
m_audio_device->m_client.set_callback(run_audio, this);
|
||||
}
|
||||
|
||||
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_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 &left_in, sample &right_in, sample &left_out, sample &right_out) {
|
||||
|
||||
command_ring_buffer::command cmd;
|
||||
while (m_osc.get(cmd)) {
|
||||
string name = cmd.m_name;
|
||||
//cerr<<name<<endl;
|
||||
if (name=="/start") {
|
||||
m_left_renderer->set_playing(true);
|
||||
m_right_renderer->set_playing(true);
|
||||
}
|
||||
if (name=="/pause") {
|
||||
m_left_renderer->set_playing(false);
|
||||
m_right_renderer->set_playing(false);
|
||||
}
|
||||
if (name=="/ratio") {
|
||||
m_left_renderer->get_params()->m_ratio = cmd.get_float(0);
|
||||
m_right_renderer->get_params()->m_ratio = cmd.get_float(0);
|
||||
}
|
||||
if (name=="/n_ratio") {
|
||||
m_left_renderer->get_params()->m_n_ratio = cmd.get_float(0);
|
||||
m_right_renderer->get_params()->m_n_ratio = cmd.get_float(0);
|
||||
}
|
||||
if (name=="/fft1_start") {
|
||||
m_left_renderer->get_params()->m_fft1_start = cmd.get_int(0);
|
||||
m_right_renderer->get_params()->m_fft1_start = cmd.get_int(0);
|
||||
}
|
||||
if (name=="/fft1_end") {
|
||||
m_left_renderer->get_params()->m_fft1_end = cmd.get_int(0);
|
||||
m_right_renderer->get_params()->m_fft1_end = cmd.get_int(0);
|
||||
}
|
||||
if (name=="/novelty") {
|
||||
m_left_renderer->get_params()->m_usage_importance = cmd.get_float(0);
|
||||
m_right_renderer->get_params()->m_usage_importance = cmd.get_float(0);
|
||||
}
|
||||
if (name=="/stickyness") {
|
||||
m_left_renderer->get_params()->m_stickyness = cmd.get_float(0);
|
||||
m_right_renderer->get_params()->m_stickyness = cmd.get_float(0);
|
||||
}
|
||||
if (name=="/autotune") {
|
||||
m_left_renderer->set_autotune(cmd.get_float(0));
|
||||
m_right_renderer->set_autotune(cmd.get_float(0));
|
||||
}
|
||||
if (name=="/restart_audio") {
|
||||
start_audio();
|
||||
}
|
||||
if (name=="/volume") {
|
||||
m_left_renderer->set_volume(cmd.get_float(0)*10);
|
||||
m_right_renderer->set_volume(cmd.get_float(0)*10);
|
||||
}
|
||||
if (name=="/search_algo") {
|
||||
switch(cmd.get_int(0)) {
|
||||
case 0: m_left_renderer->set_search_algo(renderer::BASIC); break;
|
||||
case 1: m_left_renderer->set_search_algo(renderer::REV_BASIC); break;
|
||||
case 2: m_left_renderer->set_search_algo(renderer::SYNAPTIC); break;
|
||||
case 3: m_left_renderer->set_search_algo(renderer::SYNAPTIC_SLIDE); break;
|
||||
}
|
||||
switch(cmd.get_int(0)) {
|
||||
case 0: m_right_renderer->set_search_algo(renderer::BASIC); break;
|
||||
case 1: m_right_renderer->set_search_algo(renderer::REV_BASIC); break;
|
||||
case 2: m_right_renderer->set_search_algo(renderer::SYNAPTIC); break;
|
||||
case 3: m_right_renderer->set_search_algo(renderer::SYNAPTIC_SLIDE); break;
|
||||
}
|
||||
}
|
||||
if (name=="/n_mix") {
|
||||
m_left_renderer->set_n_mix(cmd.get_float(0));
|
||||
m_right_renderer->set_n_mix(cmd.get_float(0));
|
||||
}
|
||||
if (name=="/target_mix") {
|
||||
m_left_renderer->set_target_mix(cmd.get_float(0));
|
||||
m_right_renderer->set_target_mix(cmd.get_float(0));
|
||||
}
|
||||
if (name=="/record") {
|
||||
m_left_renderer->set_playing(true);
|
||||
m_right_renderer->set_playing(true);
|
||||
m_audio_device->start_recording(cmd.get_string(0));
|
||||
}
|
||||
if (name=="/stop") {
|
||||
m_audio_device->stop_recording();
|
||||
m_left_renderer->set_playing(false);
|
||||
m_right_renderer->set_playing(false);
|
||||
}
|
||||
if (name=="/boredom") {
|
||||
m_left_renderer->get_source().set_usage_falloff(cmd.get_float(0));
|
||||
m_right_renderer->get_source().set_usage_falloff(cmd.get_float(0));
|
||||
}
|
||||
if (name=="/synapses") {
|
||||
m_left_renderer->get_params()->m_num_synapses=cmd.get_int(0);
|
||||
m_right_renderer->get_params()->m_num_synapses=cmd.get_int(0);
|
||||
}
|
||||
if (name=="/search-stretch") {
|
||||
m_left_renderer->set_stretch(cmd.get_int(0));
|
||||
m_right_renderer->set_stretch(cmd.get_int(0));
|
||||
}
|
||||
if (name=="/slide-error") {
|
||||
m_left_renderer->set_slide_error(cmd.get_int(0));
|
||||
m_right_renderer->set_slide_error(cmd.get_int(0));
|
||||
}
|
||||
if (name=="/stereo") {
|
||||
m_stereo_mode = cmd.get_int(0);
|
||||
m_left_renderer->reset();
|
||||
m_right_renderer->reset();
|
||||
}
|
||||
if (name=="/mic") {
|
||||
m_mic_mode = cmd.get_int(0);
|
||||
}
|
||||
}
|
||||
|
||||
left_out.zero();
|
||||
right_out.zero();
|
||||
if (!pthread_mutex_trylock(m_brain_mutex)) {
|
||||
|
||||
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(right_out.get_length(),
|
||||
right_out.get_non_const_buffer(),
|
||||
bs);
|
||||
} else {
|
||||
right_out=left_out;
|
||||
}
|
||||
pthread_mutex_unlock(m_brain_mutex);
|
||||
} else {
|
||||
//cerr<<"audio no lock..."<<endl;
|
||||
}
|
||||
}
|
||||
51
app/audio_thread.h
Normal file
51
app/audio_thread.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (C) 2015 Dave Griffiths
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "spiralcore/OSC_server.h"
|
||||
#include "spiralcore/audio.h"
|
||||
#include "process_thread.h"
|
||||
#include "renderer.h"
|
||||
#include "block_stream.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace spiralcore {
|
||||
|
||||
class audio_thread {
|
||||
public:
|
||||
audio_thread(process_thread &p);
|
||||
~audio_thread();
|
||||
|
||||
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();
|
||||
|
||||
OSC_server m_osc;
|
||||
process_thread &m_process_thread;
|
||||
pthread_mutex_t* m_brain_mutex;
|
||||
bool m_stereo_mode;
|
||||
bool m_mic_mode;
|
||||
};
|
||||
|
||||
}
|
||||
47
app/feedback.cpp
Normal file
47
app/feedback.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (C) 2015 Dave Griffiths
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "feedback.h"
|
||||
#include "sound_items.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace spiralcore;
|
||||
using namespace std;
|
||||
|
||||
feedback::feedback(string address) :
|
||||
m_osc(address)
|
||||
{
|
||||
m_osc.run();
|
||||
}
|
||||
|
||||
|
||||
void feedback::poll(QStatusBar *s, sound_items *sound_items) {
|
||||
command_ring_buffer::command cmd;
|
||||
|
||||
while (m_osc.get(cmd)) {
|
||||
string name = cmd.m_name;
|
||||
if (name=="/report") {
|
||||
s->showMessage(QString(cmd.get_string(0)));
|
||||
}
|
||||
if (name=="/sound-item") {
|
||||
sound_items->change_colour(cmd.get_string(0),
|
||||
cmd.get_string(1));
|
||||
}
|
||||
if (name=="/sound-item-refresh") {
|
||||
sound_items->recolour();
|
||||
}
|
||||
}
|
||||
}
|
||||
37
app/feedback.h
Normal file
37
app/feedback.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (C) 2015 Dave Griffiths
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <string>
|
||||
#include <QtGui>
|
||||
#include <QStatusBar>
|
||||
#include "spiralcore/OSC_server.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace spiralcore {
|
||||
class sound_items;
|
||||
|
||||
class feedback {
|
||||
public:
|
||||
feedback(std::string address);
|
||||
void poll(QStatusBar *s, sound_items *sound_items);
|
||||
|
||||
private:
|
||||
|
||||
OSC_server m_osc;
|
||||
};
|
||||
|
||||
}
|
||||
93
app/generated/ui_sample.h
Normal file
93
app/generated/ui_sample.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/********************************************************************************
|
||||
** Form generated from reading UI file 'sampleSy5241.ui'
|
||||
**
|
||||
** Created: Sat Jul 11 10:24:07 2015
|
||||
** by: Qt User Interface Compiler version 4.8.1
|
||||
**
|
||||
** WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SAMPLESY5241_H
|
||||
#define SAMPLESY5241_H
|
||||
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtGui/QAction>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QButtonGroup>
|
||||
#include <QtGui/QCheckBox>
|
||||
#include <QtGui/QHBoxLayout>
|
||||
#include <QtGui/QHeaderView>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Ui_FormSample
|
||||
{
|
||||
public:
|
||||
QHBoxLayout *horizontalLayout;
|
||||
QCheckBox *checkBox;
|
||||
QLabel *labelSampleName;
|
||||
QLabel *labelSampleInfo;
|
||||
QPushButton *pushButton;
|
||||
|
||||
void setupUi(QWidget *FormSample)
|
||||
{
|
||||
if (FormSample->objectName().isEmpty())
|
||||
FormSample->setObjectName(QString::fromUtf8("FormSample"));
|
||||
FormSample->resize(400, 46);
|
||||
horizontalLayout = new QHBoxLayout(FormSample);
|
||||
horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
|
||||
checkBox = new QCheckBox(FormSample);
|
||||
checkBox->setObjectName(QString::fromUtf8("checkBox"));
|
||||
QFont font;
|
||||
font.setFamily(QString::fromUtf8("Comic Sans MS"));
|
||||
font.setBold(true);
|
||||
font.setWeight(75);
|
||||
checkBox->setFont(font);
|
||||
|
||||
horizontalLayout->addWidget(checkBox);
|
||||
|
||||
labelSampleName = new QLabel(FormSample);
|
||||
labelSampleName->setObjectName(QString::fromUtf8("labelSampleName"));
|
||||
labelSampleName->setFont(font);
|
||||
|
||||
horizontalLayout->addWidget(labelSampleName);
|
||||
|
||||
labelSampleInfo = new QLabel(FormSample);
|
||||
labelSampleInfo->setObjectName(QString::fromUtf8("labelSampleInfo"));
|
||||
labelSampleInfo->setFont(font);
|
||||
|
||||
horizontalLayout->addWidget(labelSampleInfo);
|
||||
|
||||
pushButton = new QPushButton(FormSample);
|
||||
pushButton->setObjectName(QString::fromUtf8("pushButton"));
|
||||
pushButton->setFont(font);
|
||||
|
||||
horizontalLayout->addWidget(pushButton);
|
||||
|
||||
|
||||
retranslateUi(FormSample);
|
||||
|
||||
QMetaObject::connectSlotsByName(FormSample);
|
||||
} // setupUi
|
||||
|
||||
void retranslateUi(QWidget *FormSample)
|
||||
{
|
||||
FormSample->setWindowTitle(QApplication::translate("FormSample", "Form", 0, QApplication::UnicodeUTF8));
|
||||
checkBox->setText(QApplication::translate("FormSample", "active", 0, QApplication::UnicodeUTF8));
|
||||
labelSampleName->setText(QApplication::translate("FormSample", "TextLabel", 0, QApplication::UnicodeUTF8));
|
||||
labelSampleInfo->setText(QApplication::translate("FormSample", "TextLabel", 0, QApplication::UnicodeUTF8));
|
||||
pushButton->setText(QApplication::translate("FormSample", "delete", 0, QApplication::UnicodeUTF8));
|
||||
} // retranslateUi
|
||||
|
||||
};
|
||||
|
||||
namespace Ui {
|
||||
class FormSample: public Ui_FormSample {};
|
||||
} // namespace Ui
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // SAMPLESY5241_H
|
||||
1207
app/generated/ui_samplebrain.h
Normal file
1207
app/generated/ui_samplebrain.h
Normal file
File diff suppressed because it is too large
Load Diff
BIN
app/icon/samplebrain-icon.icns
Normal file
BIN
app/icon/samplebrain-icon.icns
Normal file
Binary file not shown.
BIN
app/images/at.jpg
Normal file
BIN
app/images/at.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
app/images/at.png
Normal file
BIN
app/images/at.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
app/images/pause.png
Normal file
BIN
app/images/pause.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
BIN
app/images/play.png
Normal file
BIN
app/images/play.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
BIN
app/images/record.png
Normal file
BIN
app/images/record.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
BIN
app/images/stop.png
Normal file
BIN
app/images/stop.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
1
app/notes.txt
Normal file
1
app/notes.txt
Normal file
@@ -0,0 +1 @@
|
||||
macdeplyqt
|
||||
211
app/process_thread.cpp
Normal file
211
app/process_thread.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
// Copyright (C) 2015 Dave Griffiths
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "process_thread.h"
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include "status.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
using namespace spiralcore;
|
||||
using namespace std;
|
||||
|
||||
static void _process(void *c) {
|
||||
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_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;
|
||||
}
|
||||
|
||||
void process_thread::process() {
|
||||
command_ring_buffer::command cmd;
|
||||
|
||||
while(true) {
|
||||
while (m_osc.get(cmd)) {
|
||||
string name = cmd.m_name;
|
||||
//cerr<<name<<endl;
|
||||
if (name=="/load_sample") {
|
||||
pthread_mutex_lock(m_brain_mutex);
|
||||
m_source.load_sound(cmd.get_string(0),brain::MIX);
|
||||
pthread_mutex_unlock(m_brain_mutex);
|
||||
}
|
||||
if (name=="/delete_sample") {
|
||||
pthread_mutex_lock(m_brain_mutex);
|
||||
m_source.delete_sound(cmd.get_string(0));
|
||||
pthread_mutex_unlock(m_brain_mutex);
|
||||
}
|
||||
if (name=="/activate_sound") {
|
||||
pthread_mutex_lock(m_brain_mutex);
|
||||
m_source.activate_sound(cmd.get_string(0),1);
|
||||
pthread_mutex_unlock(m_brain_mutex);
|
||||
}
|
||||
if (name=="/deactivate_sound") {
|
||||
pthread_mutex_lock(m_brain_mutex);
|
||||
m_source.activate_sound(cmd.get_string(0),0);
|
||||
pthread_mutex_unlock(m_brain_mutex);
|
||||
}
|
||||
if (name=="/source_block_size") {
|
||||
m_source_block_size = cmd.get_int(0);
|
||||
}
|
||||
if (name=="/source_overlap") {
|
||||
m_source_overlap = m_source_block_size*cmd.get_float(0);
|
||||
}
|
||||
if (name=="/generate_brain") {
|
||||
pthread_mutex_lock(m_brain_mutex);
|
||||
m_source.init(m_source_block_size, m_source_overlap, m_window_type);
|
||||
search_params p(1,0,0,100,0);
|
||||
m_source.build_synapses_fixed(p);
|
||||
m_left_renderer->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));
|
||||
}
|
||||
}
|
||||
#ifdef WIN32
|
||||
Sleep(1);
|
||||
#else
|
||||
usleep(500);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
cerr<<"loading window type session "<<m_target_window_type<<endl;
|
||||
|
||||
ifs||m_source;
|
||||
ifs||m_left_target;
|
||||
ifs||m_right_target;
|
||||
ifs.close();
|
||||
pthread_mutex_unlock(m_brain_mutex);
|
||||
}
|
||||
|
||||
void process_thread::save_session(const std::string &filename) {
|
||||
pthread_mutex_lock(m_brain_mutex);
|
||||
ofstream ofs(filename.c_str(),ios::binary);
|
||||
u32 version=0;
|
||||
ofs||version;
|
||||
ofs||(*m_left_renderer);
|
||||
ofs||(*m_right_renderer);
|
||||
ofs||m_source_block_size||m_source_overlap;
|
||||
ofs||m_target_block_size||m_target_overlap;
|
||||
|
||||
cerr<<"saving window type session "<<m_target_window_type<<endl;
|
||||
|
||||
ofs||m_window_type||m_target_window_type;
|
||||
ofs||m_source;
|
||||
ofs||m_left_target;
|
||||
ofs||m_right_target;
|
||||
ofs.close();
|
||||
pthread_mutex_unlock(m_brain_mutex);
|
||||
}
|
||||
69
app/process_thread.h
Normal file
69
app/process_thread.h
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright (C) 2015 Dave Griffiths
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "spiralcore/OSC_server.h"
|
||||
#include "brain.h"
|
||||
#include "renderer.h"
|
||||
#include "block_stream.h"
|
||||
#define HAVE_STRUCT_TIMESPEC
|
||||
#include <pthread.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace spiralcore {
|
||||
|
||||
class process_thread {
|
||||
public:
|
||||
process_thread();
|
||||
~process_thread();
|
||||
|
||||
pthread_mutex_t* m_brain_mutex;
|
||||
|
||||
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();
|
||||
|
||||
void load_source(const std::string &filename);
|
||||
void save_source(const std::string &filename);
|
||||
|
||||
void load_session(const std::string &filename);
|
||||
void save_session(const std::string &filename);
|
||||
|
||||
// only for use in mutex
|
||||
brain m_source, m_left_target, m_right_target;
|
||||
|
||||
private:
|
||||
OSC_server m_osc;
|
||||
u32 m_source_block_size;
|
||||
float m_source_overlap;
|
||||
u32 m_target_block_size;
|
||||
float m_target_overlap;
|
||||
window::type m_window_type;
|
||||
window::type m_target_window_type;
|
||||
pthread_t *m_thread;
|
||||
|
||||
// only use in mutex obvs...
|
||||
renderer *m_left_renderer;
|
||||
renderer *m_right_renderer;
|
||||
block_stream *m_block_stream;
|
||||
};
|
||||
|
||||
}
|
||||
44
app/qtmain.cpp
Normal file
44
app/qtmain.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (C) 2015 Dave Griffiths
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include <QtGui>
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include "process_thread.h"
|
||||
#include "audio_thread.h"
|
||||
//#include "pitchshift.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main( int argc , char *argv[] ){
|
||||
QApplication app(argc, argv);
|
||||
MainWindow mainWin;
|
||||
mainWin.show();
|
||||
|
||||
cerr<<"Qt version: "<<qVersion()<<endl;
|
||||
|
||||
//pitchshift::init(44100);
|
||||
|
||||
process_thread pt;
|
||||
audio_thread at(pt);
|
||||
pt.register_renderer(at.m_left_renderer, at.m_right_renderer, at.m_block_stream);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
50
app/samplebrain.pro
Normal file
50
app/samplebrain.pro
Normal file
@@ -0,0 +1,50 @@
|
||||
######################################################################
|
||||
# Automatically generated by qmake (2.01a) Sun Jul 5 17:49:45 2015
|
||||
######################################################################
|
||||
|
||||
TEMPLATE = app
|
||||
TARGET = samplebrain
|
||||
DEPENDPATH += . 2
|
||||
INCLUDEPATH += . 2
|
||||
|
||||
QT += core gui widgets
|
||||
|
||||
# Input
|
||||
HEADERS += MainWindow.h \
|
||||
generated/ui_samplebrain.h \
|
||||
|
||||
SOURCES += MainWindow.cpp \
|
||||
sound_items.cpp \
|
||||
audio_thread.cpp \
|
||||
process_thread.cpp \
|
||||
feedback.cpp \
|
||||
qtmain.cpp \
|
||||
../brain/src/block.cpp \
|
||||
../brain/src/brain.cpp \
|
||||
../brain/src/fft.cpp \
|
||||
../brain/src/mfcc.cpp \
|
||||
../brain/src/renderer.cpp \
|
||||
../brain/src/search_params.cpp \
|
||||
../brain/src/status.cpp \
|
||||
../brain/src/window.cpp \
|
||||
../brain/src/block_stream.cpp \
|
||||
../brain/src/aquila/filter/MelFilterBank.cpp \
|
||||
../brain/src/aquila/filter/MelFilter.cpp \
|
||||
../brain/src/aquila/transform/Dct.cpp \
|
||||
../brain/src/spiralcore/sample.cpp \
|
||||
../brain/src/spiralcore/ring_buffer.cpp \
|
||||
../brain/src/spiralcore/command_ring_buffer.cpp \
|
||||
../brain/src/spiralcore/portaudio_client.cpp \
|
||||
../brain/src/spiralcore/audio.cpp \
|
||||
../brain/src/spiralcore/OSC_server.cpp \
|
||||
../brain/src/spiralcore/allocator.cpp \
|
||||
../brain/src/spiralcore/stream.cpp
|
||||
|
||||
INCLUDEPATH += ../brain/src
|
||||
LIBS += -L.. -lportaudio -lfftw3 -lsndfile -llo -ldl -lpthread -lm
|
||||
CONFIG+=debug
|
||||
|
||||
QMAKE_CXXFLAGS += -Wall -Wno-unused -std=c++11
|
||||
|
||||
# assets
|
||||
RESOURCES = samplebrain.qrc
|
||||
9
app/samplebrain.qrc
Normal file
9
app/samplebrain.qrc
Normal file
@@ -0,0 +1,9 @@
|
||||
<RCC>
|
||||
<qresource prefix="images">
|
||||
<file>images/at.png</file>
|
||||
<file>images/pause.png</file>
|
||||
<file>images/play.png</file>
|
||||
<file>images/record.png</file>
|
||||
<file>images/stop.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
128
app/sound_items.cpp
Normal file
128
app/sound_items.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
// Copyright (C) 2016 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.
|
||||
|
||||
#include <QtGui>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include "spiralcore/types.h"
|
||||
|
||||
#include "sound_items.h"
|
||||
|
||||
using namespace spiralcore;
|
||||
using namespace std;
|
||||
|
||||
sound_items::sound_items():
|
||||
m_current_sound_id(0)
|
||||
{
|
||||
}
|
||||
|
||||
sound_items::sound_item &sound_items::add(QVBoxLayout *container, const string &name, bool enabled) {
|
||||
sound_item si;
|
||||
si.m_filename = name;
|
||||
si.m_id = m_current_sound_id++;
|
||||
QString style("background-color:lightgrey;");
|
||||
|
||||
si.m_container = new QHBoxLayout();
|
||||
si.m_container->setSpacing(10);
|
||||
si.m_container->setMargin(0);
|
||||
si.m_container->setContentsMargins(0,0,0,0);
|
||||
|
||||
si.m_enable = new QCheckBox();
|
||||
si.m_enable->setChecked(enabled);
|
||||
si.m_enable->setStyleSheet(style);
|
||||
si.m_enable->setContentsMargins(0,0,0,0);
|
||||
|
||||
si.m_container->addWidget(si.m_enable);
|
||||
|
||||
si.m_label = new QLabel();
|
||||
QFileInfo fi(QString::fromStdString(name));
|
||||
si.m_label->setText(fi.fileName());
|
||||
si.m_label->setStyleSheet(style);
|
||||
si.m_label->setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::Minimum);
|
||||
QFont font;
|
||||
font.setFamily(QString::fromUtf8("Comic Sans MS"));
|
||||
font.setBold(true);
|
||||
font.setWeight(75);
|
||||
si.m_label->setFont(font);
|
||||
si.m_label->setContentsMargins(0,0,0,0);
|
||||
|
||||
si.m_container->addWidget(si.m_label);
|
||||
|
||||
si.m_del = new QPushButton();
|
||||
si.m_del->setText("x");
|
||||
si.m_del->setMaximumWidth(20);
|
||||
si.m_del->setMaximumHeight(20);
|
||||
si.m_del->setStyleSheet(style);
|
||||
si.m_del->setContentsMargins(0,0,0,0);
|
||||
|
||||
si.m_container->addWidget(si.m_del);
|
||||
|
||||
container->addLayout(si.m_container);
|
||||
|
||||
m_sound_items.push_back(si);
|
||||
return m_sound_items[m_sound_items.size()-1];
|
||||
}
|
||||
|
||||
void sound_items::clear() {
|
||||
for (auto &si:m_sound_items) {
|
||||
delete si.m_enable;
|
||||
delete si.m_del;
|
||||
delete si.m_label;
|
||||
delete si.m_container;
|
||||
}
|
||||
m_sound_items.clear();
|
||||
}
|
||||
|
||||
void sound_items::recolour() {
|
||||
u32 c=0;
|
||||
for (auto &si:m_sound_items) {
|
||||
QString style("background-color:lightblue;");
|
||||
if (c%2==0) style="background-color:pink;";
|
||||
si.m_enable->setStyleSheet(style);
|
||||
si.m_del->setStyleSheet(style);
|
||||
si.m_label->setStyleSheet(style);
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
void sound_items::change_colour(const std::string &name, const std::string &colour) {
|
||||
for (auto &si:m_sound_items) {
|
||||
if (si.m_filename==name) {
|
||||
QString style("background-color:"+QString::fromStdString(colour)+";");
|
||||
si.m_enable->setStyleSheet(style);
|
||||
si.m_del->setStyleSheet(style);
|
||||
si.m_label->setStyleSheet(style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sound_items::remove(const string &name) {
|
||||
for (auto i=m_sound_items.begin(); i!=m_sound_items.end(); ++i) {
|
||||
if (i->m_filename==name) {
|
||||
// not sure why deleteLater-ing the container does not
|
||||
// remove the children (like it does with delete)
|
||||
i->m_container->deleteLater();
|
||||
i->m_enable->deleteLater();
|
||||
i->m_label->deleteLater();
|
||||
i->m_del->deleteLater();
|
||||
m_sound_items.erase(i);
|
||||
recolour();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
app/sound_items.h
Normal file
60
app/sound_items.h
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (C) 2016 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.
|
||||
|
||||
#include <QtGui>
|
||||
#include <QCheckBox>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QHBoxLayout>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace spiralcore {
|
||||
|
||||
class sound_items {
|
||||
public:
|
||||
sound_items();
|
||||
|
||||
class sound_item {
|
||||
public:
|
||||
int m_id;
|
||||
std::string m_filename;
|
||||
// can't find a way to address these via qt
|
||||
QCheckBox *m_enable;
|
||||
QPushButton *m_del;
|
||||
QLabel *m_label;
|
||||
QHBoxLayout *m_container;
|
||||
};
|
||||
|
||||
// arg - need to return it to stitch up the mapper which needs
|
||||
// to belong to the main window??
|
||||
sound_item &add(QVBoxLayout *container, const std::string &name, bool enabled);
|
||||
void remove(const std::string &name);
|
||||
void clear();
|
||||
void recolour();
|
||||
void change_colour(const std::string &name, const std::string &colour);
|
||||
|
||||
|
||||
std::vector<sound_item> m_sound_items;
|
||||
|
||||
private:
|
||||
int m_current_sound_id;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user