big directory re-org

This commit is contained in:
Dave Griffiths
2022-09-04 11:38:20 +01:00
parent 72b042f0a6
commit ca3edd4515
231 changed files with 253 additions and 332 deletions

186
app/MainWindow.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

Binary file not shown.

BIN
app/images/at.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
app/images/stop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

1
app/notes.txt Normal file
View File

@@ -0,0 +1 @@
macdeplyqt

211
app/process_thread.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
};
}