Compare commits

..

49 Commits

Author SHA1 Message Date
dave griffiths 8449f710fb Merge branch 'pr1' into 'main'
Little housekeeping

See merge request then-try-this/samplebrain!15
2022-10-31 18:36:00 +00:00
Dave Griffiths 69dc3721be trying to set the path again for qt/windows ci build 2022-10-31 10:07:23 +00:00
aeiouaeiouaeiouaeiouaeiouaeiou f057cc6159
Use CMAKE_AUTORCC 2022-10-31 12:55:21 +03:00
aeiouaeiouaeiouaeiouaeiouaeiou 33bba6d337
Extend .gitignore 2022-10-31 12:55:10 +03:00
Dave Griffiths 16d04c8faf trying to set the path again for qt/windows ci build 2022-10-31 09:52:49 +00:00
Dave Griffiths 994d002796 trying to set the patch for qt/windows ci build 2022-10-31 09:39:18 +00:00
Dave Griffiths 0ab061eb0e back to qt5 again to attempt win ci to work (choco doesn't seem to have qt6 yet) 2022-10-30 18:37:28 +00:00
Dave Griffiths 5573355c8e trying win ci - adding python 2022-10-30 12:01:38 +00:00
Dave Griffiths 07fa73ecab trying win ci 2022-10-30 11:45:04 +00:00
Dave Griffiths 5566284cd8 trying win ci 2022-10-30 11:40:15 +00:00
Dave Griffiths b0454ed2f4 trying win ci 2022-10-30 11:33:47 +00:00
Dave Griffiths e22a501aa7 trying removing deps 2022-10-30 11:24:46 +00:00
Dave Griffiths 7a02dcfa3c switched (back) to qt6 2022-10-29 13:49:15 +01:00
Dave Griffiths b983408bd7 Merge branch 'samplebrain-parallel-synapse-generation' into main 2022-10-29 13:14:34 +01:00
Dave Griffiths fa44d2b4c7 added openmp to cmake 2022-10-29 13:13:16 +01:00
Dave Griffiths 8e7a9abe1a removed pro file 2022-10-29 13:00:53 +01:00
Dave Griffiths 65ea2080be Merge remote-tracking branch 'origin/development' into main 2022-10-29 12:53:34 +01:00
Dave Griffiths edf2071467 added reddit 2022-10-29 12:39:18 +01:00
Dave Griffiths 2e517e3bff changelog update 2022-10-29 08:48:13 +01:00
Dave Griffiths 1b766822f6 new version README update 2022-10-29 08:35:34 +01:00
Dave Griffiths bc8002a9f0 added target filename to GUI - not adding brain session or directory as less need for it/more clutter... partially fixes: #76 2022-10-23 10:06:23 +01:00
Dave Griffiths f9f3557b79 sorted file paths so we have separate ones for each dialog - fixes: #75 2022-10-23 09:34:46 +01:00
Dave Griffiths c4499ce7c9 commented out unused and confusing old code - fixes: #28 2022-10-20 21:22:23 +01:00
Dave Griffiths 46ab0a131a optimisation from Claude - fixes: #27 2022-10-20 21:15:27 +01:00
Dave Griffiths 884c8ad91f resources location 2022-10-20 21:12:58 +01:00
Dave Griffiths 1d03e9addd ci tweak 2022-10-14 22:33:17 +01:00
Dave Griffiths af44ac43f0 more cmake qt fiddling 2022-10-14 22:29:25 +01:00
Dave Griffiths b971435101 cmake qt fiddling 2022-10-14 22:25:38 +01:00
Dave Griffiths 7bc12ac0be cmake build fixes 2022-10-14 22:18:52 +01:00
dave griffiths 8038fdd9c2 Merge branch 'upgrade-to-cmake' into 'main'
Upgrade build system from qmake to cmake

See merge request then-try-this/samplebrain!11
2022-10-14 20:34:17 +00:00
dave griffiths bbdcd4b29c Merge branch 'main' into 'upgrade-to-cmake'
# Conflicts:
#   app/MainWindow.h
#   app/SettingsDialog.h
2022-10-14 20:31:07 +00:00
Dave Griffiths 385563e64e forgot to add flac 2022-10-14 21:24:56 +01:00
Dave Griffiths e1c8e0ea67 added more soundfile formats to the loading dialog and new error report when it can't load 2022-10-14 20:30:12 +01:00
Dave Griffiths b5fd6dd3e0 added osc ports to the settings interface, bumped the version num 2022-10-14 19:23:07 +01:00
Dave Griffiths 5e347f7f13 made the 3 osc ports configurable via (cross-platform) config scripts and move them outside of well used ranges for UDP 2022-10-14 18:27:59 +01:00
fshstk cf06a21160 Add Gitlab CI script 2022-10-12 15:22:37 +02:00
fshstk 6471b1e066 Clean up CMakeLists
- Remove redundant libraries
- Change compile definitions to CMake variables
2022-10-12 15:21:51 +02:00
fshstk 7d7a7d24a2 Remove Qt .pro file
CMakeLists.txt now does everything we need
2022-10-12 14:56:16 +02:00
fshstk 2c1a3692e7 Update building.md
- Add info about installing cmake
- Change build instructions from qmake to cmake
- Remove info about installing deps
  We don't need to do this anymore. CMake will do it automatically at
  configure-time!
2022-10-12 14:56:16 +02:00
fshstk 30e16d80d9 Add libsndfile dependency 2022-10-12 14:56:16 +02:00
fshstk 2743caa02a Add portaudio dependency 2022-10-12 14:56:16 +02:00
fshstk 572d6a127c Add liblo dependency 2022-10-12 14:56:16 +02:00
fshstk 6aa25397de Add fftw3 dependency 2022-10-12 14:56:16 +02:00
fshstk 55e5427ec4 Fix path to .ui files 2022-10-12 14:56:16 +02:00
fshstk c2e923bcee Ignore build folder
This should cover all files generated by the build system...
2022-10-12 14:56:16 +02:00
fshstk ddf7f8538a Fix CMakeLists syntax
target_compile_options requires the PUBLIC/PRIVATE keyword. I don't know
why the qmake2cmake script doesn't provide the correct syntax here...
2022-10-12 14:56:16 +02:00
fshstk 1dc55a982c Run qmake2cmake command
Command used:
qmake2cmake_all . --min-qt-version 6.2.4
2022-10-12 14:56:07 +02:00
Dave Griffiths 5469a8f253 added build instructions for ubuntu 22.04 fixes: #66 2022-10-07 08:39:45 +01:00
Claude Heiland-Allen 8aa0dee3d1 parallelize synapse generation using OpenMP
- only tested on Debian Linux with a 16-thread amd64 CPU
- Windows may need DLLs to be shipped with the EXE
- using `-fopenmp` should be made optional via qmake somehow
  (without the flag, parallelization pragmas are ignored
  and it reverts to serial operation)
- assumes `status::update()` among other code is thread-safe,
  it seems to work on my machine without issues...
2022-09-27 13:19:04 +01:00
30 changed files with 979 additions and 580 deletions

6
.gitignore vendored
View File

@ -1,3 +1,7 @@
*.rej
*.orig
.DS_Store
*.ini
build
*.*~ *.*~
*.o *.o

24
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,24 @@
build-ubuntu:
stage: build
image: ubuntu:22.04
script:
- apt-get update
- apt-get install -y git cmake g++ freeglut3-dev qtbase5-dev qt5-qmake qtbase5-dev-tools
- mkdir -p build
- cd build
- cmake ..
- cmake --build . --target samplebrain
build-win64:
tags:
- "windows"
before_script:
- choco install -y cmake python qt5-default
- $env:Path += ';C:\Program Files\CMake\bin'
stage: build
script:
- set CMAKE_PREFIX_PATH=C:\Qt\5.15.2\mingw81_64
- mkdir build
- cd build
- cmake ..
- cmake --build . --target samplebrain

81
CMakeLists.txt Normal file
View File

@ -0,0 +1,81 @@
cmake_minimum_required(VERSION 3.16)
project(samplebrain VERSION 1.0 LANGUAGES C CXX)
include(Dependencies.cmake)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Set up AUTOMOC and some sensible defaults for runtime execution
# When using Qt 6.3, you can replace the code block below with
# qt_standard_project_setup()
set(CMAKE_AUTOMOC ON)
include(GNUInstallDirs)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt5 REQUIRED COMPONENTS Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui Widgets)
find_package(OpenMP)
add_executable(samplebrain WIN32 MACOSX_BUNDLE
app/MainWindow.cpp app/MainWindow.h
app/SettingsDialog.cpp app/SettingsDialog.h
app/audio_thread.cpp
app/feedback.cpp
app/process_thread.cpp
app/qtmain.cpp
app/samplebrain.qrc
app/sound_items.cpp
brain/src/aquila/filter/MelFilter.cpp
brain/src/aquila/filter/MelFilterBank.cpp
brain/src/aquila/transform/Dct.cpp
brain/src/block.cpp
brain/src/block_stream.cpp
brain/src/brain.cpp
brain/src/fft.cpp
brain/src/mfcc.cpp
brain/src/renderer.cpp
brain/src/search_params.cpp
brain/src/spiralcore/OSC_server.cpp
brain/src/spiralcore/allocator.cpp
brain/src/spiralcore/audio.cpp
brain/src/spiralcore/command_ring_buffer.cpp
brain/src/spiralcore/portaudio_client.cpp
brain/src/spiralcore/ring_buffer.cpp
brain/src/spiralcore/sample.cpp
brain/src/spiralcore/stream.cpp
brain/src/status.cpp
brain/src/window.cpp
app/gui/samplebrain.ui
app/gui/settings.ui
)
target_include_directories(samplebrain PRIVATE
.
brain/src
)
target_link_libraries(samplebrain PRIVATE
Qt5::Core
Qt5::Gui
Qt5::Widgets
fftw3
lo_shared
portaudio
sndfile
)
if(OpenMP_CXX_FOUND)
target_link_libraries(samplebrain PUBLIC OpenMP::OpenMP_CXX)
endif()
install(TARGETS samplebrain
BUNDLE DESTINATION .
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
# Consider using qt_generate_deploy_app_script() for app deployment if
# the project can use Qt 6.3. In that case rerun qmake2cmake with
# --min-qt-version=6.3.

49
Dependencies.cmake Normal file
View File

@ -0,0 +1,49 @@
################################################################################
# FetchContent
################################################################################
include(FetchContent)
################################################################################
# fftw3
################################################################################
FetchContent_Declare(
fftw3
URL http://fftw.org/fftw-3.3.10.tar.gz
URL_HASH MD5=8ccbf6a5ea78a16dbc3e1306e234cc5c)
FetchContent_MakeAvailable(fftw3)
include_directories(${fftw3_SOURCE_DIR}/api)
################################################################################
# liblo
################################################################################
FetchContent_Declare(
liblo
URL http://downloads.sourceforge.net/liblo/liblo-0.31.tar.gz
URL_HASH MD5=14378c1e74c58e777fbb4fcf33ac5315)
FetchContent_MakeAvailable(liblo)
add_subdirectory(${liblo_SOURCE_DIR}/cmake)
################################################################################
# PortAudio
################################################################################
FetchContent_Declare(
portaudio
URL http://files.portaudio.com/archives/pa_stable_v190700_20210406.tgz
URL_HASH MD5=ad319249932c6794b551d954b8844402)
FetchContent_MakeAvailable(portaudio)
################################################################################
# libsndfile
################################################################################
FetchContent_Declare(
libsndfile
GIT_REPOSITORY https://github.com/libsndfile/libsndfile
GIT_TAG 1.1.0)
FetchContent_MakeAvailable(libsndfile)

View File

@ -34,6 +34,10 @@ both the target and brain samples). The original samples used to
create the demo session [can be found here for create the demo session [can be found here for
testing](https://static.thentrythis.org/samplebrain/samples/). testing](https://static.thentrythis.org/samplebrain/samples/).
# Community
* https://www.reddit.com/r/samplebrain/
# Download # Download
As this is experimental non-commercial software (only originally As this is experimental non-commercial software (only originally
@ -41,12 +45,16 @@ written to run on a couple of computers!) you will have to bear with
us as we gradually stabilise things based on your feedback. There us as we gradually stabilise things based on your feedback. There
might currently be problems running it on 64bit Windows. might currently be problems running it on 64bit Windows.
* **Windows**: [samplebrain_0.18.4_win.zip](https://static.thentrythis.org/samplebrain/samplebrain_0.18.4_win.zip) * **Windows**: [samplebrain_0.18.5_win.zip](https://static.thentrythis.org/samplebrain/samplebrain_0.18.5_win.zip)
* **Mac (intel/m1)**: [samplebrain_0.18.4_macintel.zip](https://static.thentrythis.org/samplebrain/samplebrain_0.18.4_macintel.app.zip) * **Mac (intel/m1)**: [samplebrain_0.18.5_macintel.zip](https://static.thentrythis.org/samplebrain/samplebrain_0.18.5_macintel.app.zip)
Changes in 0.18.4: New audio device settings window and updated Changes in 0.18.5 (relased 28/10/22):
windows build. Better default block size, tool tip tweaks and fixes
for dark themes by [Claude Heiland-Allen](https://mathr.co.uk/). * Target sound filename shown (and tells you if you don't have one)
* More soundfile formats supported (aiff,aifc,au,snd,fasttracker xi,flac)
* New configurable OSC ports in settings
* Warning boxes if the OSC network connection fails
* File path memory per-dialog rather than global
For old versions see the [changelog](changelog.md) For old versions see the [changelog](changelog.md)

View File

@ -27,9 +27,16 @@
using namespace std; using namespace std;
MainWindow::MainWindow() : MainWindow::MainWindow(const string &port, const string &audio_port, const string &process_port, QSettings *settings) :
m_last_file("."), m_last_sound_file("."),
m_feedback("8890") m_last_target_file("."),
m_last_brain_file("."),
m_last_session_file("."),
m_last_recording_file("."),
m_feedback(port),
m_audio_port(audio_port),
m_process_port(process_port),
m_format_string("Microsoft WAV (*.wav);;SGI/Apple AIFF (*.aiff);;SGI/Apple AIFC (*.aifc);;Sun/DEC/NeXT AU (*.au);;Sun/DEC/NeXT SND (*.snd);;Fasttracker 2 XI (*.xi);;Free Lossless Audio Codec FLAC (*.flac);;All files (*.*)")
{ {
m_sound_item_enable_mapper = new QSignalMapper(this); m_sound_item_enable_mapper = new QSignalMapper(this);
m_sound_item_delete_mapper = new QSignalMapper(this); m_sound_item_delete_mapper = new QSignalMapper(this);
@ -49,7 +56,7 @@ MainWindow::MainWindow() :
m_Ui.brain_contents->setSpacing(0); m_Ui.brain_contents->setSpacing(0);
m_Ui.brain_contents->setContentsMargins(0,0,0,0); m_Ui.brain_contents->setContentsMargins(0,0,0,0);
m_settings_dialog = new SettingsDialog(this); m_settings_dialog = new SettingsDialog(this,settings);
// add default local dest // add default local dest
// turn on first one // turn on first one
@ -59,8 +66,8 @@ MainWindow::MainWindow() :
for (int i=0; i<10; i++) { for (int i=0; i<10; i++) {
osc_destination d; osc_destination d;
d.m_id=i; d.m_id=i;
d.m_audio_address = lo_address_new_from_url("osc.udp://localhost:8888"); d.m_audio_address = lo_address_new_from_url(string("osc.udp://localhost:"+m_audio_port).c_str());
d.m_process_address = lo_address_new_from_url("osc.udp://localhost:8889"); d.m_process_address = lo_address_new_from_url(string("osc.udp://localhost:"+m_process_port).c_str());
if (i==0) d.m_enabled=true; if (i==0) d.m_enabled=true;
else d.m_enabled=false; else d.m_enabled=false;
add_gui_address(d,enable_mapper); add_gui_address(d,enable_mapper);
@ -154,6 +161,12 @@ void MainWindow::init_from_session(const string &filename) {
m_Ui.spinBoxSlideError->setValue(r.get_slide_error()); m_Ui.spinBoxSlideError->setValue(r.get_slide_error());
// target // target
if (t.get_samples().size()>0) {
// extract target filename from brain sample
string fn = t.get_samples().begin()->m_filename;
m_Ui.labelTargetSound->setText("loaded: "+QFileInfo(QString::fromStdString(fn)).fileName());
}
m_Ui.spinBoxBlockSizeTarget->setValue(t.get_block_size()); m_Ui.spinBoxBlockSizeTarget->setValue(t.get_block_size());
m_Ui.doubleSpinBoxBlockOverlapTarget->setValue(t.get_overlap()/(float)t.get_block_size()); m_Ui.doubleSpinBoxBlockOverlapTarget->setValue(t.get_overlap()/(float)t.get_block_size());

View File

@ -18,7 +18,8 @@
#include <QDirIterator> #include <QDirIterator>
#include <QFileDialog> #include <QFileDialog>
#include <QLineEdit> #include <QLineEdit>
#include "ui_samplebrain.h" #include <QMessageBox>
#include "gui/ui_samplebrain.h"
#include "SettingsDialog.h" #include "SettingsDialog.h"
#include <iostream> #include <iostream>
@ -32,12 +33,22 @@
using namespace std; using namespace std;
using namespace spiralcore; using namespace spiralcore;
class QSettings;
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {
Q_OBJECT Q_OBJECT
public: public:
MainWindow(); MainWindow(const string &port, const string &audio_port, const string &process_port, QSettings *settings);
void message(const string &msg) {
QMessageBox::information(this,"problem",msg.c_str(), QMessageBox::Ok);
}
bool ok() {
return m_feedback.ok();
}
// all this to work around liblo's use of varargs... // all this to work around liblo's use of varargs...
void send_audio_osc(const char *name, const char *types) { void send_audio_osc(const char *name, const char *types) {
@ -102,344 +113,360 @@ protected:
private slots: private slots:
void play_slot() { send_audio_osc("/start",""); } void play_slot() { send_audio_osc("/start",""); }
void stop_slot() { send_audio_osc("/pause",""); } void stop_slot() { send_audio_osc("/pause",""); }
void ratio_slot(int s) { void ratio_slot(int s) {
send_audio_osc("/ratio","f",s/100.0f); send_audio_osc("/ratio","f",s/100.0f);
m_Ui.doubleSpinBoxRatio->setValue(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() {
QString path=QFileDialog::getOpenFileName(this,
QString("Select an audio file"),
m_last_target_file,
m_format_string);
if (m_last_target_file!="") {
m_last_target_file=path;
m_Ui.labelTargetSound->setText("loaded: "+QFileInfo(path).fileName());
send_process_osc("/load_target","s",m_last_target_file.toStdString().c_str());
} }
void ratio_slot(double s) { }
send_audio_osc("/ratio","f",s); void target_block_size(int s) { send_process_osc("/target_block_size","i",s); }
m_Ui.sliderRatio->setValue(s*100); 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 n_ratio_slot(int s) { void block_overlap(double s) { send_process_osc("/source_overlap","f",s); }
send_audio_osc("/n_ratio","f",s/100.0f); void fft_spectrum_size(int) {}
m_Ui.doubleSpinBoxNRatio->setValue(s/100.0f); void generate() { send_process_osc("/generate_brain",""); }
} void load_sound() {
void n_ratio_slot(double s) { QString path=QFileDialog::getOpenFileName(this,
send_audio_osc("/n_ratio","f",s); QString("Select a wav file"),
m_Ui.sliderNRatio->setValue(s*100); m_last_sound_file,
} m_format_string);
void autotune(int s) { if (path!="") {
send_audio_osc("/autotune","f",s/100.0f); m_last_sound_file=path;
m_Ui.doubleSpinBoxAutotune->setValue(s/100.0f); send_process_osc("/load_sample","s",m_last_sound_file.toStdString().c_str());
} sound_items::sound_item &si = m_sound_items.add(m_Ui.brain_contents, m_last_sound_file.toStdString(),true);
void autotune(double s) { QObject::connect(si.m_enable, SIGNAL(clicked()), m_sound_item_enable_mapper, SLOT(map()));
send_audio_osc("/autotune","f",s); m_sound_item_enable_mapper->setMapping(si.m_enable, si.m_id);
m_Ui.sliderAutotune->setValue(s*100); 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 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() { void load_sounds() {
m_last_file=QFileDialog::getExistingDirectory(this, QString path=QFileDialog::getExistingDirectory(this,
QString("Select a directory"), QString("Select a directory of wav files"),
m_last_file); m_last_directory_file);
if (path!="") {
m_last_directory_file=path;
QDirIterator dirIt(m_last_directory_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());
QDirIterator dirIt(m_last_file,QDirIterator::Subdirectories); sound_items::sound_item &si = m_sound_items.add(m_Ui.brain_contents, dirIt.filePath().toStdString(),true);
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);
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) { void select_all() {
// search for this id... for (auto &si:m_sound_items.m_sound_items) {
for (auto &si:m_sound_items.m_sound_items) { si.m_enable->setChecked(true);
if (si.m_id==id) { send_process_osc("/activate_sound","s",si.m_filename.c_str());
send_process_osc("/delete_sample","s",si.m_filename.c_str()); }
m_sound_items.remove(si.m_filename); }
// iterator is now invalidated...
return; 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 clear_brain() { }
for (auto &si:m_sound_items.m_sound_items) {
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()); send_process_osc("/delete_sample","s",si.m_filename.c_str());
m_sound_items.remove(si.m_filename);
// iterator is now invalidated...
return;
} }
m_sound_items.clear();
} }
void restart_audio() { send_audio_osc("/restart_audio",""); } }
void clear_brain() {
void brain_shape(int n) { send_process_osc("/window_type","i",n); } for (auto &si:m_sound_items.m_sound_items) {
void target_shape(int n) { send_process_osc("/target_window_type","i",n); } send_process_osc("/delete_sample","s",si.m_filename.c_str());
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++;
} }
m_sound_items.clear();
}
void restart_audio() { send_audio_osc("/restart_audio",""); }
void stop_record() { void brain_shape(int n) { send_process_osc("/window_type","i",n); }
send_audio_osc("/stop",""); 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 load_brain() { void record() {
m_last_file=QFileDialog::getOpenFileName( if (m_save_wav=="") {
this, m_last_recording_file=QFileDialog::getSaveFileName(this,
QString("Select a brain file"), QString("Select a wav file"),
m_last_file, m_last_recording_file,
QString("Brains (*.brain)")); QString("Sounds (*.wav);;All files (*.*)"));
m_save_wav = m_last_recording_file.toStdString();
send_process_osc("/load_brain","s",m_last_file.toStdString().c_str()); // chop off .wav
} size_t pos = m_save_wav.find_last_of(".");
void save_brain() { if (pos!=string::npos) {
m_last_file=QFileDialog::getSaveFileName( m_save_wav = m_save_wav.substr(0,pos);
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,m_settings_dialog);
}
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;
} }
} }
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() {
QString path=QFileDialog::getOpenFileName(this,
QString("Select a brain file"),
m_last_brain_file,
QString("Brains (*.brain);;All files (*.*)"));
if (path!="") {
m_last_brain_file=path;
send_process_osc("/load_brain","s",m_last_brain_file.toStdString().c_str());
}
}
void save_brain() {
QString path=QFileDialog::getSaveFileName(this,
QString("Select a brain file"),
m_last_brain_file,
QString("Brains (*.brain);;All files (*.*)"));
if (path!="") {
m_last_brain_file=path;
send_process_osc("/save_brain","s",m_last_brain_file.toStdString().c_str());
}
}
void load_session() {
QString path=QFileDialog::getOpenFileName(this,
QString("Select a session file"),
m_last_session_file,
QString("Sessions *.samplebrain (*.samplebrain);;All files (*.*)"));
if (path!="") {
m_last_session_file=path;
send_process_osc("/load_session","s",m_last_session_file.toStdString().c_str());
init_from_session(m_last_session_file.toStdString());
}
}
void save_session() {
QString path=QFileDialog::getSaveFileName(this,
QString("Select a session file"),
m_last_session_file,
QString("Sessions *.samplebrain (*.samplebrain)"));
if (path!="") {
m_last_session_file=path;
send_process_osc("/save_session","s",m_last_session_file.toStdString().c_str());
}
}
void update_status() {
m_feedback.poll(m_Ui.statusbar,&m_sound_items,m_settings_dialog);
}
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+":"+m_audio_port).c_str());
d.m_process_address = lo_address_new_from_url(string(url+":"+m_process_port).c_str());
// start sending messages here
d.m_enabled=true;
} else {
// stop sending messages here
d.m_enabled=false;
}
}
void settings() { void settings() {
m_settings_dialog->show(); m_settings_dialog->show();
} }
private: private:
/////////////////////////////////////////////// ///////////////////////////////////////////////
// we want to be able to send out to // we want to be able to send out to
// multiple addresses over the network // multiple addresses over the network
//////////////////////////////////////////////// ////////////////////////////////////////////////
// we want to be able to send out to // we want to be able to send out to
// multiple addresses over the network // multiple addresses over the network
class osc_destination { class osc_destination {
public: public:
int m_id; int m_id;
lo_address m_audio_address; lo_address m_audio_address;
lo_address m_process_address; lo_address m_process_address;
// can't find a way to address these via qt // can't find a way to address these via qt
QLineEdit *m_address; QLineEdit *m_address;
QCheckBox *m_enable; QCheckBox *m_enable;
bool m_enabled; bool m_enabled;
}; };
vector<osc_destination> m_destinations; vector<osc_destination> m_destinations;
void init_from_session(const string &filename); void init_from_session(const string &filename);
void add_gui_address(osc_destination &dest, void add_gui_address(osc_destination &dest,
QSignalMapper* enable_mapper); QSignalMapper* enable_mapper);
string m_save_wav; string m_save_wav;
QString m_last_file; QString m_last_sound_file;
unsigned int m_record_id; QString m_last_target_file;
Ui_MainWindow m_Ui; QString m_last_directory_file;
feedback m_feedback; QString m_last_brain_file;
QSignalMapper* m_sound_item_enable_mapper; QString m_last_session_file;
QSignalMapper* m_sound_item_delete_mapper; QString m_last_recording_file;
sound_items m_sound_items; 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;
SettingsDialog *m_settings_dialog; SettingsDialog *m_settings_dialog;
audio_thread *m_audio_thread; audio_thread *m_audio_thread;
string m_audio_port;
string m_process_port;
QString m_format_string;
}; };

View File

@ -24,12 +24,16 @@
using namespace std; using namespace std;
SettingsDialog::SettingsDialog(MainWindow *parent): SettingsDialog::SettingsDialog(MainWindow *parent, QSettings *settings):
m_device(""), m_device(""),
m_parent(parent), m_parent(parent),
m_buffersize(2048), m_buffersize(2048),
m_samplerate(44100) { m_samplerate(44100),
m_settings(settings) {
m_Ui.setupUi(this); m_Ui.setupUi(this);
m_Ui.guiOSCLineEdit->setText(settings->value("gui_port").toByteArray().constData());
m_Ui.processOSCLineEdit->setText(settings->value("process_port").toByteArray().constData());
m_Ui.audioOSCLineEdit->setText(settings->value("audio_port").toByteArray().constData());
} }
void SettingsDialog::connect() { void SettingsDialog::connect() {

View File

@ -20,7 +20,8 @@
#include <QtGui> #include <QtGui>
#include <QDialog> #include <QDialog>
#include <QLineEdit> #include <QLineEdit>
#include "ui_settings.h" #include <QSettings>
#include "gui/ui_settings.h"
#include <iostream> #include <iostream>
#include <lo/lo.h> #include <lo/lo.h>
@ -36,7 +37,7 @@ class SettingsDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
SettingsDialog(MainWindow *parent); SettingsDialog(MainWindow *parent, QSettings *settings);
Ui_SettingsDialog m_Ui; Ui_SettingsDialog m_Ui;
string m_device; string m_device;
@ -62,14 +63,27 @@ class SettingsDialog : public QDialog
void reject() { hide(); } void reject() { hide(); }
void apply() { connect(); } void apply() { connect(); }
void gui_port(QString str) {
m_settings->setValue("gui_port",str);
}
void process_port(QString str) {
m_settings->setValue("process_port",str);
}
void audio_port(QString str) {
m_settings->setValue("audio_port",str);
}
private: private:
void connect(); void connect();
MainWindow *m_parent; MainWindow *m_parent;
unsigned int m_buffersize; unsigned int m_buffersize;
unsigned int m_samplerate; unsigned int m_samplerate;
QSettings *m_settings;
}; };
#endif #endif

View File

@ -20,26 +20,23 @@
using namespace spiralcore; using namespace spiralcore;
using namespace std; using namespace std;
audio_thread::audio_thread(process_thread &p) : audio_thread::audio_thread(const string &port, process_thread &p) :
m_audio_device(NULL), m_audio_device(NULL),
m_osc("8888"), m_osc(port),
m_process_thread(p), m_process_thread(p),
m_brain_mutex(p.m_brain_mutex), m_brain_mutex(p.m_brain_mutex),
m_stereo_mode(false), m_stereo_mode(false),
m_mic_mode(false), m_mic_mode(false),
m_bufsize(2048), m_bufsize(2048),
m_samplerate(44100), m_samplerate(44100),
m_device("") m_device("") {
{
// start_audio();
pthread_mutex_lock(m_brain_mutex); pthread_mutex_lock(m_brain_mutex);
m_left_renderer = new renderer(p.m_source,p.m_left_target); 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_right_renderer = new renderer(p.m_source,p.m_right_target);
m_block_stream = new block_stream(); m_block_stream = new block_stream();
pthread_mutex_unlock(m_brain_mutex); pthread_mutex_unlock(m_brain_mutex);
m_osc.run(); m_osc.run();
// it this threadsafe?
// m_audio_device->report_devices();
} }
static bool state = 1; static bool state = 1;

View File

@ -26,12 +26,12 @@ namespace spiralcore {
class audio_thread { class audio_thread {
public: public:
audio_thread(process_thread &p); audio_thread(const string &port, process_thread &p);
~audio_thread(); ~audio_thread();
void start_audio(); void start_audio();
void restart_audio(const string device, unsigned int samplerate, unsigned int bufsize); void restart_audio(const string device, unsigned int samplerate, unsigned int bufsize);
bool ok() { return m_osc.ok(); }
void process(sample &left_in, sample &right_in, sample &left_out, sample &right_out); void process(sample &left_in, sample &right_in, sample &left_out, sample &right_out);
static void run_audio(void* c, unsigned int frames); static void run_audio(void* c, unsigned int frames);

View File

@ -29,6 +29,7 @@ class feedback {
public: public:
feedback(std::string address); feedback(std::string address);
void poll(QStatusBar *s, sound_items *sound_items, SettingsDialog *settings); void poll(QStatusBar *s, sound_items *sound_items, SettingsDialog *settings);
bool ok() { return m_osc.ok(); }
private: private:

View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -7,11 +7,11 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1188</width> <width>1188</width>
<height>898</height> <height>939</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>samplebrain 0.18.4</string> <string>samplebrain 0.18.5</string>
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_4"> <layout class="QVBoxLayout" name="verticalLayout_4">
@ -728,6 +728,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="labelTargetSound">
<property name="text">
<string>no target sound loaded</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="pushButtonLoadTarget"> <widget class="QPushButton" name="pushButtonLoadTarget">
<property name="font"> <property name="font">
@ -1112,8 +1119,8 @@
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>17</width>
<height>40</height> <height>13</height>
</size> </size>
</property> </property>
</spacer> </spacer>
@ -1466,7 +1473,7 @@
<string/> <string/>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../app/samplebrain.qrc"> <iconset resource="../samplebrain.qrc">
<normaloff>:/images/images/play.png</normaloff>:/images/images/play.png</iconset> <normaloff>:/images/images/play.png</normaloff>:/images/images/play.png</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
@ -1493,7 +1500,7 @@
<string/> <string/>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../app/samplebrain.qrc"> <iconset resource="../samplebrain.qrc">
<normaloff>:/images/images/pause.png</normaloff>:/images/images/pause.png</iconset> <normaloff>:/images/images/pause.png</normaloff>:/images/images/pause.png</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
@ -1513,7 +1520,7 @@
<string/> <string/>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../app/samplebrain.qrc"> <iconset resource="../samplebrain.qrc">
<normaloff>:/images/images/record.png</normaloff>:/images/images/record.png</iconset> <normaloff>:/images/images/record.png</normaloff>:/images/images/record.png</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
@ -1533,7 +1540,7 @@
<string/> <string/>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../app/samplebrain.qrc"> <iconset resource="../samplebrain.qrc">
<normaloff>:/images/images/stop.png</normaloff>:/images/images/stop.png</iconset> <normaloff>:/images/images/stop.png</normaloff>:/images/images/stop.png</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
@ -1599,7 +1606,7 @@
<string/> <string/>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../app/samplebrain.qrc"> <iconset resource="../samplebrain.qrc">
<normaloff>:/images/images/settings.png</normaloff>:/images/images/settings.png</iconset> <normaloff>:/images/images/settings.png</normaloff>:/images/images/settings.png</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
@ -1632,7 +1639,7 @@
<string/> <string/>
</property> </property>
<property name="pixmap"> <property name="pixmap">
<pixmap resource="../app/samplebrain.qrc">:/images/images/at.png</pixmap> <pixmap resource="../samplebrain.qrc">:/images/images/at.png</pixmap>
</property> </property>
</widget> </widget>
</item> </item>
@ -1643,7 +1650,8 @@
<widget class="QStatusBar" name="statusbar"/> <widget class="QStatusBar" name="statusbar"/>
</widget> </widget>
<resources> <resources>
<include location="../app/samplebrain.qrc"/> <include location="../samplebrain.qrc"/>
<include location="../samplebrain.qrc"/>
</resources> </resources>
<connections> <connections>
<connection> <connection>

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>400</width> <width>438</width>
<height>522</height> <height>656</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -31,7 +31,13 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QComboBox" name="deviceComboBox"/> <widget class="QComboBox" name="deviceComboBox">
<property name="font">
<font>
<family>Comic Sans MS</family>
</font>
</property>
</widget>
</item> </item>
</layout> </layout>
</item> </item>
@ -57,6 +63,11 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="font">
<font>
<family>Comic Sans MS</family>
</font>
</property>
<property name="text"> <property name="text">
<string>44100</string> <string>44100</string>
</property> </property>
@ -73,7 +84,7 @@
</font> </font>
</property> </property>
<property name="text"> <property name="text">
<string>(note: this currently should probably match your sample file's input rate as no conversion is run on them - yet)</string> <string>note: this currently should probably match your sample file's input rate as no conversion is run on them - yet</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@ -98,6 +109,11 @@
</item> </item>
<item> <item>
<widget class="QComboBox" name="buffersizeComboBox"> <widget class="QComboBox" name="buffersizeComboBox">
<property name="font">
<font>
<family>Comic Sans MS</family>
</font>
</property>
<property name="currentIndex"> <property name="currentIndex">
<number>5</number> <number>5</number>
</property> </property>
@ -180,6 +196,112 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="label_9">
<property name="font">
<font>
<family>Comic Sans MS</family>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>restart needed for the ports below to update</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_6">
<property name="font">
<font>
<family>Comic Sans MS</family>
</font>
</property>
<property name="text">
<string>gui osc port</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="guiOSCLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Comic Sans MS</family>
</font>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_7">
<property name="font">
<font>
<family>Comic Sans MS</family>
</font>
</property>
<property name="text">
<string>process osc port</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="processOSCLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Comic Sans MS</family>
</font>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_8">
<property name="font">
<font>
<family>Comic Sans MS</family>
</font>
</property>
<property name="text">
<string>audio osc port</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="audioOSCLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Comic Sans MS</family>
</font>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QPushButton" name="applyPushButton"> <widget class="QPushButton" name="applyPushButton">
<property name="font"> <property name="font">
@ -218,8 +340,8 @@
<slot>accept()</slot> <slot>accept()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>231</x> <x>244</x>
<y>358</y> <y>642</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>157</x> <x>157</x>
@ -234,8 +356,8 @@
<slot>reject()</slot> <slot>reject()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>299</x> <x>312</x>
<y>364</y> <y>642</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>286</x> <x>286</x>
@ -266,8 +388,8 @@
<slot>apply()</slot> <slot>apply()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>112</x> <x>125</x>
<y>321</y> <y>592</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>4</x> <x>4</x>
@ -298,8 +420,8 @@
<slot>buffersize(QString)</slot> <slot>buffersize(QString)</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>326</x> <x>390</x>
<y>131</y> <y>215</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>395</x> <x>395</x>
@ -307,11 +429,62 @@
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection>
<sender>guiOSCLineEdit</sender>
<signal>textChanged(QString)</signal>
<receiver>SettingsDialog</receiver>
<slot>gui_port(QString)</slot>
<hints>
<hint type="sourcelabel">
<x>346</x>
<y>432</y>
</hint>
<hint type="destinationlabel">
<x>401</x>
<y>419</y>
</hint>
</hints>
</connection>
<connection>
<sender>processOSCLineEdit</sender>
<signal>textChanged(QString)</signal>
<receiver>SettingsDialog</receiver>
<slot>process_port(QString)</slot>
<hints>
<hint type="sourcelabel">
<x>356</x>
<y>482</y>
</hint>
<hint type="destinationlabel">
<x>398</x>
<y>479</y>
</hint>
</hints>
</connection>
<connection>
<sender>audioOSCLineEdit</sender>
<signal>textChanged(QString)</signal>
<receiver>SettingsDialog</receiver>
<slot>audio_port(QString)</slot>
<hints>
<hint type="sourcelabel">
<x>374</x>
<y>511</y>
</hint>
<hint type="destinationlabel">
<x>398</x>
<y>517</y>
</hint>
</hints>
</connection>
</connections> </connections>
<slots> <slots>
<slot>output_device(QString)</slot> <slot>output_device(QString)</slot>
<slot>samplerate(QString)</slot> <slot>samplerate(QString)</slot>
<slot>buffersize(QString)</slot> <slot>buffersize(QString)</slot>
<slot>apply()</slot> <slot>apply()</slot>
<slot>gui_port(QString)</slot>
<slot>audio_port(QString)</slot>
<slot>process_port(QString)</slot>
</slots> </slots>
</ui> </ui>

View File

@ -32,8 +32,8 @@ static void* _process(void *c) {
return NULL; return NULL;
} }
process_thread::process_thread() : process_thread::process_thread(const string &port) :
m_osc("8889"), m_osc(port),
m_source_block_size(1000), m_source_block_size(1000),
m_source_overlap(0.75), m_source_overlap(0.75),
m_target_block_size(1000), m_target_block_size(1000),

View File

@ -25,9 +25,9 @@
namespace spiralcore { namespace spiralcore {
class process_thread { class process_thread {
public: public:
process_thread(); process_thread(const string &port);
~process_thread(); ~process_thread();
pthread_mutex_t* m_brain_mutex; pthread_mutex_t* m_brain_mutex;
@ -47,10 +47,13 @@ public:
void load_session(const std::string &filename); void load_session(const std::string &filename);
void save_session(const std::string &filename); void save_session(const std::string &filename);
bool ok() { return m_osc.ok(); }
// only for use in mutex // only for use in mutex
brain m_source, m_left_target, m_right_target; brain m_source, m_left_target, m_right_target;
private: private:
OSC_server m_osc; OSC_server m_osc;
u32 m_source_block_size; u32 m_source_block_size;
float m_source_overlap; float m_source_overlap;
@ -64,6 +67,6 @@ private:
renderer *m_left_renderer; renderer *m_left_renderer;
renderer *m_right_renderer; renderer *m_right_renderer;
block_stream *m_block_stream; block_stream *m_block_stream;
}; };
} }

View File

@ -19,22 +19,54 @@
#include <iostream> #include <iostream>
#include <unistd.h> #include <unistd.h>
#include <QtGui> #include <QtGui>
#include <QSettings>
#include "MainWindow.h" #include "MainWindow.h"
#include "process_thread.h" #include "process_thread.h"
#include "audio_thread.h" #include "audio_thread.h"
#include "status.h"
using namespace std; using namespace std;
int main( int argc , char *argv[] ){ int main( int argc , char *argv[] ){
QApplication app(argc, argv);
MainWindow mainWin;
mainWin.show();
process_thread pt;
audio_thread at(pt);
pt.register_renderer(at.m_left_renderer, at.m_right_renderer, at.m_block_stream);
mainWin.set_audio_thread(&at);
return app.exec(); QApplication app(argc, argv);
cerr<<"Qt version: "<<qVersion()<<endl;
QSettings settings("thentrythis", "samplebrain");
// slight over-use of OSC servers here, but the are packaged nicely for
// threadsafe (nonblocking) communication, and it's useful to expose all
// moving parts for external control (i.e. the processing and the audio)
if (!settings.contains("gui_port")) settings.setValue("gui_port", "62345");
if (!settings.contains("audio_port")) settings.setValue("audio_port", "62346");
if (!settings.contains("process_port")) settings.setValue("process_port", "62347");
string gui_port = settings.value("gui_port").toByteArray().constData();
string audio_port = settings.value("audio_port").toByteArray().constData();
string process_port = settings.value("process_port").toByteArray().constData();
status::set_port(gui_port);
MainWindow mainWin(gui_port,audio_port,process_port,&settings);
mainWin.show();
process_thread pt(process_port);
audio_thread at(audio_port,pt);
pt.register_renderer(at.m_left_renderer, at.m_right_renderer, at.m_block_stream);
mainWin.set_audio_thread(&at);
if (!at.ok()) {
mainWin.message("problem starting audio thread on port "+audio_port);
}
if (!pt.ok()) {
mainWin.message("problem starting process thread on port "+process_port);
}
if (!mainWin.ok()) {
mainWin.message("problem starting gui thread on port "+gui_port);
}
return app.exec();
} }

View File

@ -112,6 +112,7 @@ void block::process(const sample &pcm, sample &fft, sample &mfcc, float &freq) {
// calculate fft // calculate fft
std::vector<std::complex<double> > mfspec; std::vector<std::complex<double> > mfspec;
mfspec.reserve(m_block_size);
for (u32 i=0; i<m_block_size; ++i) { for (u32 i=0; i<m_block_size; ++i) {
mfspec.push_back(std::complex<double>(m_fftw->m_spectrum[i][0], mfspec.push_back(std::complex<double>(m_fftw->m_spectrum[i][0],
m_fftw->m_spectrum[i][1])); m_fftw->m_spectrum[i][1]));

View File

@ -79,6 +79,7 @@ void block_stream::init(u32 block_size, u32 overlap, window::type t, bool ditchp
m_window.set_current_type(t); m_window.set_current_type(t);
m_blocks.clear(); m_blocks.clear();
m_blocks.reserve(MAX_BLOCKS);
sample dummy(block_size); sample dummy(block_size);
for (u32 i=0; i<MAX_BLOCKS; i++) { for (u32 i=0; i<MAX_BLOCKS; i++) {
m_blocks.push_back(block(0,"dummy",dummy,44100,m_window)); m_blocks.push_back(block(0,"dummy",dummy,44100,m_window));

View File

@ -16,6 +16,7 @@
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#include <atomic>
#include <sndfile.h> #include <sndfile.h>
#include <float.h> #include <float.h>
#include <spiralcore/audio.h> #include <spiralcore/audio.h>
@ -69,6 +70,8 @@ void brain::load_sound(std::string filename, stereo_mode mode) {
delete[] temp; delete[] temp;
m_samples.push_back(sound(filename,s)); m_samples.push_back(sound(filename,s));
status::update("loaded %s",filename.c_str()); status::update("loaded %s",filename.c_str());
} else {
status::update("problem loading %s",filename.c_str());
} }
} }
@ -226,6 +229,7 @@ u32 brain::rev_search(const block &target, const search_params &params) {
return furthest_index; return furthest_index;
} }
/*
// really slow - every to every comparison of blocks calculating average distance // really slow - every to every comparison of blocks calculating average distance
double brain::calc_average_diff(search_params &params) { double brain::calc_average_diff(search_params &params) {
double diff=0; double diff=0;
@ -242,10 +246,12 @@ void brain::build_synapses_thresh(search_params &params, double thresh) {
m_average_error = calc_average_diff(params)*thresh; m_average_error = calc_average_diff(params)*thresh;
double err = m_average_error*thresh; double err = m_average_error*thresh;
u32 brain_size = m_blocks.size(); u32 brain_size = m_blocks.size();
u32 outer_index = 0; std::atomic<u32> progress{0};
for (auto &i : m_blocks) { #pragma omp parallel for
for (u32 outer_index = 0; outer_index < brain_size; ++outer_index) {
auto &i = m_blocks[outer_index];
u32 index = 0; u32 index = 0;
status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100)); status::update("building synapses %d%%",(int)(progress/(float)brain_size*100));
for (auto &j : m_blocks) { for (auto &j : m_blocks) {
if (index!=outer_index) { if (index!=outer_index) {
// collect connections that are under threshold in closeness // collect connections that are under threshold in closeness
@ -256,30 +262,33 @@ void brain::build_synapses_thresh(search_params &params, double thresh) {
} }
++index; ++index;
} }
++outer_index; ++progress;
} }
} }
*/
void brain::build_synapses_fixed(search_params &params) { void brain::build_synapses_fixed(search_params &params) {
//m_average_error = calc_average_diff(params)*thresh; //m_average_error = calc_average_diff(params)*thresh;
u32 brain_size = m_blocks.size(); u32 brain_size = m_blocks.size();
u32 outer_index = 0;
u32 num_synapses = NUM_FIXED_SYNAPSES; u32 num_synapses = NUM_FIXED_SYNAPSES;
if (num_synapses>=m_blocks.size()) num_synapses=m_blocks.size()-1; if (num_synapses>=m_blocks.size()) num_synapses=m_blocks.size()-1;
// need to stop the progress updates flooding osc // need to stop the progress updates flooding osc
u32 update_period = 100; u32 update_period = 100;
u32 update_tick = 0; std::atomic<u32> update_tick{0};
std::atomic<u32> progress{0};
for (auto &i:m_blocks) { #pragma omp parallel for
for (u32 outer_index = 0; outer_index < brain_size; ++outer_index) {
auto &i = m_blocks[outer_index];
if (update_tick>update_period) { if (update_tick>update_period) {
status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100)); status::update("building synapses %d%%",(int)(progress/(float)brain_size*100));
update_tick=0; update_tick=0;
} }
update_tick++; update_tick++;
u32 index = 0; u32 index = 0;
vector<pair<u32,double>> collect; vector<pair<u32,double>> collect;
collect.reserve(brain_size);
// collect comparisons to all other blocks // collect comparisons to all other blocks
for (auto &j:m_blocks) { for (auto &j:m_blocks) {
@ -304,7 +313,7 @@ void brain::build_synapses_fixed(search_params &params) {
i.get_synapse().push_back(collect[n].first); i.get_synapse().push_back(collect[n].first);
} }
++outer_index; ++progress;
} }
status::update("Done: %d synapses grown for %d blocks",num_synapses*brain_size,brain_size); status::update("Done: %d synapses grown for %d blocks",num_synapses*brain_size,brain_size);
} }

View File

@ -62,8 +62,8 @@ public:
u32 rev_search(const block &target, const search_params &params); u32 rev_search(const block &target, const search_params &params);
// synaptic search // synaptic search
double calc_average_diff(search_params &params); // double calc_average_diff(search_params &params);
void build_synapses_thresh(search_params &params, double threshold); // void build_synapses_thresh(search_params &params, double threshold);
void build_synapses_fixed(search_params &params); void build_synapses_fixed(search_params &params);
u32 search_synapses(const block &target, search_params &params); u32 search_synapses(const block &target, search_params &params);
double get_current_error() { return m_current_error; } double get_current_error() { return m_current_error; }

View File

@ -31,117 +31,106 @@ extern "C" {
#endif #endif
OSC_server::OSC_server(const string &port) : OSC_server::OSC_server(const string &port) :
m_port(port), m_port(port),
m_exit(false), m_exit(false),
m_command_ring_buffer(262144) m_command_ring_buffer(262144) {
{ cerr<<"OSC using port: ["<<port<<"]"<<endl;
//cerr<<"using port: ["<<port<<"]"<<endl; m_server = lo_server_thread_new(port.c_str(), error_handler);
m_server = lo_server_thread_new(port.c_str(), error_handler); if (m_server) {
lo_server_thread_add_method(m_server, NULL, NULL, default_handler, this); lo_server_thread_add_method(m_server, NULL, NULL, default_handler, this);
} else {
cerr<<"error opening OSC port"<<endl;
}
} }
OSC_server::~OSC_server() OSC_server::~OSC_server() {
{ m_exit=true;
m_exit=true; lo_server_thread_stop(m_server);
lo_server_thread_stop(m_server);
} }
void OSC_server::run() void OSC_server::run() {
{ if (!m_server) return;
lo_server_thread_start(m_server); lo_server_thread_start(m_server);
// while (!m_exit) usleep(1000); // while (!m_exit) usleep(1000);
} }
void OSC_server::error_handler(int num, const char *msg, const char *path) void OSC_server::error_handler(int num, const char *msg, const char *path) {
{ //cerr<<"liblo server error "<<num<<" in path "<<path<<": "<<msg<<endl;
//cerr<<"liblo server error "<<num<<" in path "<<path<<": "<<msg<<endl; cerr<<"liblo server error "<<num<<endl;
cerr<<"liblo server error "<<num<<endl;
} }
int OSC_server::default_handler(const char *path, const char *types, lo_arg **argv, int OSC_server::default_handler(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data) int argc, void *data, void *user_data) {
{ OSC_server *server = (OSC_server*)user_data;
OSC_server *server = (OSC_server*)user_data; if (!server) return -1;
unsigned int size = 0; unsigned int size = 0;
for (int i=0; i<argc; i++) for (int i=0; i<argc; i++) {
{ size+=lo_arg_size((lo_type)types[i],argv[i]);
size+=lo_arg_size((lo_type)types[i],argv[i]); // add one for the null terminator
// add one for the null terminator if (types[i]=='s') size++;
if (types[i]=='s') size++; }
}
char *newdata=new char[size];
unsigned int pos=0;
for (int i=0; i<argc; i++)
{
switch (types[i])
{
case LO_INT32:
{
if (pos+4>COMMAND_DATA_SIZE)
{
cerr<<"osc data too big for ringbuffer command"<<endl;
delete[] newdata;
return 1;
}
memcpy(newdata+pos,(char*)argv[i],4);
pos+=4;
}
break;
case LO_FLOAT:
{
if (pos+4>COMMAND_DATA_SIZE)
{
cerr<<"osc data too big for ringbuffer command"<<endl;
delete[] newdata;
return 1;
}
memcpy(newdata+pos,(char*)argv[i],4);
pos+=4;
}
break;
case LO_STRING:
{
int size=strlen(&argv[i]->s);
if (pos+size+1>COMMAND_DATA_SIZE)
{
cerr<<"osc data too big for ringbuffer command"<<endl;
delete[] newdata;
return 1;
}
memcpy(newdata+pos,&argv[i]->s,size);
newdata[pos+size]='\0';
pos+=size+1;
}
break;
default:
{
cerr<<"unsupported type: "<<types[i]<<endl;
delete[] newdata;
return 1;
}
break;
}
}
if (1)//pos==size) hmm
{
command_ring_buffer::command command(path,types,newdata,pos);
if (!server->m_command_ring_buffer.send(command))
{
//cerr<<"OSC_server - ringbuffer full!"<<endl;
}
}
else
{
cerr<<"OSC_server::default_handler: size mismatch ["<<pos<<":"<<size<<"], not sending message"<<endl;
}
char *newdata=new char[size];
unsigned int pos=0;
for (int i=0; i<argc; i++) {
switch (types[i]) {
case LO_INT32: {
if (pos+4>COMMAND_DATA_SIZE) {
cerr<<"osc data too big for ringbuffer command"<<endl;
delete[] newdata; delete[] newdata;
return 1; return 1;
}
memcpy(newdata+pos,(char*)argv[i],4);
pos+=4;
}
break;
case LO_FLOAT: {
if (pos+4>COMMAND_DATA_SIZE) {
cerr<<"osc data too big for ringbuffer command"<<endl;
delete[] newdata;
return 1;
}
memcpy(newdata+pos,(char*)argv[i],4);
pos+=4;
}
break;
case LO_STRING: {
int size=strlen(&argv[i]->s);
if (pos+size+1>COMMAND_DATA_SIZE) {
cerr<<"osc data too big for ringbuffer command"<<endl;
delete[] newdata;
return 1;
}
memcpy(newdata+pos,&argv[i]->s,size);
newdata[pos+size]='\0';
pos+=size+1;
}
break;
default: {
cerr<<"unsupported type: "<<types[i]<<endl;
delete[] newdata;
return 1;
}
break;
}
}
if (1) { //pos==size) hmm
command_ring_buffer::command command(path,types,newdata,pos);
if (!server->m_command_ring_buffer.send(command)) {
//cerr<<"OSC_server - ringbuffer full!"<<endl;
}
}
else {
cerr<<"OSC_server::default_handler: size mismatch ["<<pos<<":"<<size<<"], not sending message"<<endl;
}
delete[] newdata;
return 1;
} }

View File

@ -24,20 +24,21 @@
class OSC_server class OSC_server
{ {
public: public:
OSC_server(const std::string &port); OSC_server(const std::string &port);
~OSC_server(); ~OSC_server();
void run(); void run();
bool get(command_ring_buffer::command& command) { return m_command_ring_buffer.get(command);} bool get(command_ring_buffer::command& command) { return m_command_ring_buffer.get(command);}
bool ok() { return m_server!=NULL; }
private: private:
static int default_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data); static int default_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data);
static void error_handler(int num, const char *m, const char *path); static void error_handler(int num, const char *m, const char *path);
lo_server_thread m_server; lo_server_thread m_server;
std::string m_port; std::string m_port;
bool m_exit; bool m_exit;
command_ring_buffer m_command_ring_buffer; command_ring_buffer m_command_ring_buffer;
}; };
#endif #endif

View File

@ -22,6 +22,10 @@ using namespace std;
lo_address status::m_address = lo_address_new_from_url("osc.udp://localhost:8890"); lo_address status::m_address = lo_address_new_from_url("osc.udp://localhost:8890");
void status::set_port(const std::string &port) {
status::m_address = lo_address_new_from_url(string("osc.udp://localhost:"+port).c_str());
}
void status::_update(const std::string &msg) { void status::_update(const std::string &msg) {
lo_send(m_address,"/report","s",msg.c_str()); lo_send(m_address,"/report","s",msg.c_str());
} }

View File

@ -24,6 +24,7 @@ namespace spiralcore {
class status { class status {
public: public:
static void set_port(const std::string &port);
static void _update(const std::string &msg); static void _update(const std::string &msg);
static void update(const char *msg, ...); static void update(const char *msg, ...);
static void sound_item(const std::string &name, const std::string &colour); static void sound_item(const std::string &name, const std::string &colour);

View File

@ -1,26 +1,29 @@
# Building from source # Building from source
## Linux (Ubuntu) ## Linux (Ubuntu)
Install libraries for the sample engine (use brew on mac, MinGW on win): Install cmake:
$ sudo apt install libsndfile1-dev portaudio19-dev liblo-dev libfftw3-dev $ sudo apt install cmake
Install dependencies for the interface: Install dependencies for the interface:
$ sudo apt install build-essential qtcreator qt5-default $ sudo apt install build-essential qtcreator qt5-default
On ubuntu 22.04 it's:
$ apt install build-essential qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools
Build & run it: Build & run it:
$ mkdir build $ mkdir build
$ cd build $ cd build
$ qmake .. $ cmake ..
$ make $ cmake --build .
$ sudo make install $ ./samplebrain
$ samplebrain
## Mac ## Mac
Install libraries for sample engine: Install cmake:
$ brew install fftw portaudio liblo libsndfile $ brew install cmake
Install dependencies for the interface: Install dependencies for the interface:
@ -31,10 +34,10 @@ Build & run it:
$ mkdir build $ mkdir build
$ cd build $ cd build
$ qmake .. $ cmake ..
$ make $ cmake --build .
`samplebrain.app` should then be in the app folder for you to run. `samplebrain.app` should then be in the build folder for you to run.
# Mac build additions # Mac build additions
@ -57,3 +60,12 @@ Then edit Info.plist to add samplebrain.icns to CFBundleIconFile. Key `CFBundleI
You might also need to resign the app bundle after making any changes You might also need to resign the app bundle after making any changes
$ codesign --force --deep --sign - samplebrain.app $ codesign --force --deep --sign - samplebrain.app
# Windows (Work in progress)
* Install [MSYS2](https://www.msys2.org/)
* Install dependances via pacman
* Build with qmake as usual
* Run `windeployqt` and copy missing .dll files into release directory

View File

@ -1,5 +1,14 @@
# Changlog # Changlog
0.18.4
* **Windows**: [samplebrain_0.18.4_win.zip](https://static.thentrythis.org/samplebrain/samplebrain_0.18.4_win.zip)
* **Mac (intel/m1)**: [samplebrain_0.18.4_macintel.zip](https://static.thentrythis.org/samplebrain/samplebrain_0.18.4_macintel.app.zip)
Changes in 0.18.4: New audio device settings window and updated
windows build. Better default block size, tool tip tweaks and fixes
for dark themes by [Claude Heiland-Allen](https://mathr.co.uk/).
0.18.3 0.18.3
* **Windows**: [samplebrain_0.18.3_win.zip](https://static.thentrythis.org/samplebrain/samplebrain_0.18.3_win.zip) * **Windows**: [samplebrain_0.18.3_win.zip](https://static.thentrythis.org/samplebrain/samplebrain_0.18.3_win.zip)

11
debian/changelog vendored
View File

@ -1,6 +1,11 @@
samplebrain (0.18rc2-1ubuntu0~bionic4) bionic; urgency=medium samplebrain (0.18.5rc1-1ubuntu0~bionic1) bionic; urgency=medium
* Initial release * Target sound filename shown (and tells you if you don't have one)
* More soundfile formats supported (aiff,aifc,au,snd,fasttracker xi,flac)
* New configurable OSC ports in settings
* Warning boxes if the OSC network connection fails
* File path memory per-dialog rather than global
-- Dave Griffiths <dave@thentrythis.org> Thu, 29 Oct 2022 08:47:10 +0100
-- Dave Griffiths <dave@thentrythis.org> Thu, 08 Sep 2022 13:08:26 +0100

View File

@ -1,71 +0,0 @@
######################################################################
# 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 += app/MainWindow.h \
app/SettingsDialog.h
FORMS += gui/samplebrain.ui \
gui/settings.ui
SOURCES += app/MainWindow.cpp \
app/SettingsDialog.cpp \
app/sound_items.cpp \
app/audio_thread.cpp \
app/process_thread.cpp \
app/feedback.cpp \
app/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
INCLUDEPATH += /usr/local/include
INCLUDEPATH += /opt/homebrew/include
LIBS += -L.. -L/usr/local/lib -L/opt/homebrew/lib -lportaudio -lfftw3 -lsndfile -llo -ldl -lpthread -lm
QMAKE_CXXFLAGS += -O3 -Wall -Wno-unused -std=c++11
# assets
RESOURCES = app/samplebrain.qrc
ICON = desktop/samplebrain.icns
PREFIX = $$(PREFIX)
isEmpty(PREFIX) {
PREFIX = /usr
}
unix:desktopfile.path = $$PREFIX/share/applications/
unix:desktopfile.files = desktop/samplebrain.desktop
unix:iconfile.path = $$PREFIX/share/icons/hicolor/scalable/apps
unix:iconfile.files = desktop/samplebrain.svg
unix:metainfofile.path = $$PREFIX/share/metainfo
unix:metainfofile.files = desktop/org.thentrythis.Samplebrain.metainfo.xml
target.path = $$PREFIX/bin
INSTALLS += target desktopfile iconfile metainfofile