From 62d4574eee1d36c07f0f8191fc38e18aa48a6716 Mon Sep 17 00:00:00 2001 From: dave griffiths Date: Fri, 25 Sep 2015 09:14:01 +0100 Subject: [PATCH] fixes for autotune --- samplebrain/interface/samplebrain.ui | Bin 77398 -> 78564 bytes samplebrain/qt/MainWindow.h | 10 + samplebrain/qt/audio_thread.cpp | 199 ++++++------ samplebrain/qt/generated/ui_samplebrain.h | 368 +++++++++++----------- samplebrain/qt/qtmain.cpp | 4 +- samplebrain/qt/samplebrain.pro | 3 +- samplebrain/src/fft.cpp | 4 +- samplebrain/src/renderer.cpp | 44 ++- samplebrain/src/renderer.h | 1 + 9 files changed, 341 insertions(+), 292 deletions(-) diff --git a/samplebrain/interface/samplebrain.ui b/samplebrain/interface/samplebrain.ui index a277ec86f4b572fd26e602c0ed7d000e54f65bf4..0f6807d97e5e1a10de115b89452e3768e9c1a781 100644 GIT binary patch literal 78564 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
*UdFMj{}v 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 literal 77398 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 z@0KAgCsetValue(s*100); } + void autotune(int s) { + lo_send(m_audio_address,"/autotune","f",s/100.0f); + m_Ui.doubleSpinBoxAutotune->setValue(s/100.0f); + } + void autotune(double s) { + lo_send(m_audio_address,"/autotune","f",s); + m_Ui.sliderAutotune->setValue(s*100); + } + + void fft1_start_slot(int s) { lo_send(m_audio_address,"/fft1_start","i",s); } void fft1_end_slot(int s) { lo_send(m_audio_address,"/fft1_end","i",s); } void fft2_start_slot(int s){} // { m_renderer->get_params()->m_fft2_start=s; } diff --git a/samplebrain/qt/audio_thread.cpp b/samplebrain/qt/audio_thread.cpp index bde4b72..7ec7c87 100644 --- a/samplebrain/qt/audio_thread.cpp +++ b/samplebrain/qt/audio_thread.cpp @@ -21,121 +21,124 @@ 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_audio_device(NULL), + m_osc("8888"), + m_process_thread(p), + m_brain_mutex(p.m_brain_mutex) { - start_audio(); - pthread_mutex_lock(m_brain_mutex); - m_renderer = new renderer(p.m_source,p.m_target); - pthread_mutex_unlock(m_brain_mutex); - m_osc.run(); + start_audio(); + pthread_mutex_lock(m_brain_mutex); + m_renderer = new renderer(p.m_source,p.m_target); + 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_renderer; + state=0; + if (m_audio_device!=NULL) delete m_audio_device; + delete m_renderer; } void audio_thread::start_audio() { - if (m_audio_device!=NULL) delete m_audio_device; - m_audio_device = new audio_device("samplebrain",44100,2048); - m_audio_device->m_client.set_callback(run_audio, this); + if (m_audio_device!=NULL) delete m_audio_device; + m_audio_device = new audio_device("samplebrain",44100,2048); + 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_out, - at->m_audio_device->right_out); - at->m_audio_device->maybe_record(); - } + if (state) { + audio_thread *at = (audio_thread*)c; + at->m_audio_device->left_out.zero(); + at->process(at->m_audio_device->left_out, + at->m_audio_device->right_out); + at->m_audio_device->maybe_record(); + } } void audio_thread::process(sample &s, sample &s2) { - command_ring_buffer::command cmd; - while (m_osc.get(cmd)) { - string name = cmd.m_name; - //cerr<set_playing(true); - } - if (name=="/pause") { - m_renderer->set_playing(false); - } - if (name=="/ratio") { - m_renderer->get_params()->m_ratio = cmd.get_float(0); - } - if (name=="/n_ratio") { - m_renderer->get_params()->m_n_ratio = cmd.get_float(0); - } - if (name=="/fft1_start") { - m_renderer->get_params()->m_fft1_start = cmd.get_int(0); - } - if (name=="/fft1_end") { - m_renderer->get_params()->m_fft1_end = cmd.get_int(0); - } - if (name=="/novelty") { - m_renderer->get_params()->m_usage_importance = cmd.get_float(0); - } - if (name=="/stickyness") { - m_renderer->get_params()->m_stickyness = cmd.get_float(0); - } - if (name=="/restart_audio") { - start_audio(); - } - if (name=="/volume") { - m_renderer->set_volume(cmd.get_float(0)*10); - } - if (name=="/search_algo") { - switch(cmd.get_int(0)) { - case 0: m_renderer->set_search_algo(renderer::BASIC); break; - case 1: m_renderer->set_search_algo(renderer::REV_BASIC); break; - case 2: m_renderer->set_search_algo(renderer::SYNAPTIC); break; - case 3: m_renderer->set_search_algo(renderer::SYNAPTIC_SLIDE); break; - } - } - if (name=="/n_mix") { - m_renderer->set_n_mix(cmd.get_float(0)); - } - if (name=="/target_mix") { - m_renderer->set_target_mix(cmd.get_float(0)); - } - if (name=="/record") { - m_renderer->set_playing(true); - m_audio_device->start_recording(cmd.get_string(0)); - } - if (name=="/stop") { - m_audio_device->stop_recording(); - m_renderer->set_playing(false); - } - if (name=="/boredom") { - m_renderer->get_source().set_usage_falloff(cmd.get_float(0)); - } - if (name=="/synapses") { - m_renderer->get_params()->m_num_synapses=cmd.get_int(0); - } - if (name=="/search-stretch") { - m_renderer->set_stretch(cmd.get_int(0)); - } - if (name=="/slide-error") { - m_renderer->set_slide_error(cmd.get_int(0)); - } + command_ring_buffer::command cmd; + while (m_osc.get(cmd)) { + string name = cmd.m_name; + //cerr<set_playing(true); } + if (name=="/pause") { + m_renderer->set_playing(false); + } + if (name=="/ratio") { + m_renderer->get_params()->m_ratio = cmd.get_float(0); + } + if (name=="/n_ratio") { + m_renderer->get_params()->m_n_ratio = cmd.get_float(0); + } + if (name=="/fft1_start") { + m_renderer->get_params()->m_fft1_start = cmd.get_int(0); + } + if (name=="/fft1_end") { + m_renderer->get_params()->m_fft1_end = cmd.get_int(0); + } + if (name=="/novelty") { + m_renderer->get_params()->m_usage_importance = cmd.get_float(0); + } + if (name=="/stickyness") { + m_renderer->get_params()->m_stickyness = cmd.get_float(0); + } + if (name=="/autotune") { + m_renderer->set_autotune(cmd.get_float(0)); + } + if (name=="/restart_audio") { + start_audio(); + } + if (name=="/volume") { + m_renderer->set_volume(cmd.get_float(0)*10); + } + if (name=="/search_algo") { + switch(cmd.get_int(0)) { + case 0: m_renderer->set_search_algo(renderer::BASIC); break; + case 1: m_renderer->set_search_algo(renderer::REV_BASIC); break; + case 2: m_renderer->set_search_algo(renderer::SYNAPTIC); break; + case 3: m_renderer->set_search_algo(renderer::SYNAPTIC_SLIDE); break; + } + } + if (name=="/n_mix") { + m_renderer->set_n_mix(cmd.get_float(0)); + } + if (name=="/target_mix") { + m_renderer->set_target_mix(cmd.get_float(0)); + } + if (name=="/record") { + m_renderer->set_playing(true); + m_audio_device->start_recording(cmd.get_string(0)); + } + if (name=="/stop") { + m_audio_device->stop_recording(); + m_renderer->set_playing(false); + } + if (name=="/boredom") { + m_renderer->get_source().set_usage_falloff(cmd.get_float(0)); + } + if (name=="/synapses") { + m_renderer->get_params()->m_num_synapses=cmd.get_int(0); + } + if (name=="/search-stretch") { + m_renderer->set_stretch(cmd.get_int(0)); + } + if (name=="/slide-error") { + m_renderer->set_slide_error(cmd.get_int(0)); + } + } - s.zero(); - s2.zero(); - if (!pthread_mutex_trylock(m_brain_mutex)) { - m_renderer->process(s.get_length(),s.get_non_const_buffer()); - pthread_mutex_unlock(m_brain_mutex); + s.zero(); + s2.zero(); + if (!pthread_mutex_trylock(m_brain_mutex)) { + m_renderer->process(s.get_length(),s.get_non_const_buffer()); + pthread_mutex_unlock(m_brain_mutex); s2=s; - } else { - cerr<<"audio no lock..."< #include @@ -88,17 +88,6 @@ public: QLabel *label_29; QSlider *sliderSlideError; QSpinBox *spinBoxSlideError; - QSpacerItem *horizontalSpacer_2; - QSpacerItem *verticalSpacer_3; - QLabel *label_23; - QHBoxLayout *horizontalLayout_8; - QLabel *label_21; - QSlider *sliderNMix; - QDoubleSpinBox *doubleSpinBoxNMix; - QHBoxLayout *horizontalLayout_9; - QLabel *label_22; - QSlider *sliderTargetMix; - QDoubleSpinBox *doubleSpinBoxTargetMix; QVBoxLayout *verticalLayout_6; QLabel *label_16; QPushButton *pushButtonLoadTarget; @@ -119,9 +108,27 @@ public: QRadioButton *radioButton_rectangleTarget; QLabel *label_14; QPushButton *pushButtonGenerateTarget; + QLabel *label_23; + QHBoxLayout *horizontalLayout_22; + QLabel *label_31; + QSlider *sliderAutotune; + QDoubleSpinBox *doubleSpinBoxAutotune; + QHBoxLayout *horizontalLayout_8; + QLabel *label_21; + QSlider *sliderNMix; + QDoubleSpinBox *doubleSpinBoxNMix; + QHBoxLayout *horizontalLayout_9; + QLabel *label_22; + QSlider *sliderTargetMix; + QDoubleSpinBox *doubleSpinBoxTargetMix; QSpacerItem *verticalSpacer; - QVBoxLayout *verticalLayout_2; + QVBoxLayout *verticalLayout; QLabel *label_3; + QListWidget *listWidgetSounds; + QHBoxLayout *horizontalLayout_2; + QPushButton *pushButtonLoadSound; + QPushButton *pushButtonDeleteSound; + QPushButton *pushButtonClearBrain; QHBoxLayout *horizontalLayout_4; QLabel *label; QSpinBox *spinBoxBlockSize; @@ -129,8 +136,8 @@ public: QLabel *label_2; QDoubleSpinBox *doubleSpinBoxBlockOverlap; QGridLayout *gridLayout; - QRadioButton *radioButton_gaussian; QRadioButton *radioButton_hamming; + QRadioButton *radioButton_gaussian; QRadioButton *radioButton_dodgy; QRadioButton *radioButton_blackman; QRadioButton *radioButton_rectagle; @@ -142,14 +149,6 @@ public: QHBoxLayout *horizontalLayout_7; QPushButton *pushButtonLoadBrain; QPushButton *pushButtonSaveBrain; - QSpacerItem *verticalSpacer_2; - QVBoxLayout *verticalLayout; - QLabel *label_5; - QListWidget *listWidgetSounds; - QHBoxLayout *horizontalLayout_2; - QPushButton *pushButtonLoadSound; - QPushButton *pushButtonDeleteSound; - QPushButton *pushButtonClearBrain; QWidget *logTab; QHBoxLayout *horizontalLayout_15; QPlainTextEdit *plainTextEdit; @@ -170,7 +169,7 @@ public: { if (MainWindow->objectName().isEmpty()) MainWindow->setObjectName(QString::fromUtf8("MainWindow")); - MainWindow->resize(1220, 755); + MainWindow->resize(1012, 707); centralwidget = new QWidget(MainWindow); centralwidget->setObjectName(QString::fromUtf8("centralwidget")); verticalLayout_4 = new QVBoxLayout(centralwidget); @@ -546,81 +545,6 @@ public: verticalLayout_3->addLayout(horizontalLayout_20); - horizontalSpacer_2 = new QSpacerItem(21, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - verticalLayout_3->addItem(horizontalSpacer_2); - - verticalSpacer_3 = new QSpacerItem(240, 574, QSizePolicy::Minimum, QSizePolicy::Expanding); - - verticalLayout_3->addItem(verticalSpacer_3); - - label_23 = new QLabel(controlTab); - label_23->setObjectName(QString::fromUtf8("label_23")); - label_23->setFont(font1); - - verticalLayout_3->addWidget(label_23); - - horizontalLayout_8 = new QHBoxLayout(); - horizontalLayout_8->setObjectName(QString::fromUtf8("horizontalLayout_8")); - label_21 = new QLabel(controlTab); - label_21->setObjectName(QString::fromUtf8("label_21")); - label_21->setFont(font2); - - horizontalLayout_8->addWidget(label_21); - - sliderNMix = new QSlider(controlTab); - sliderNMix->setObjectName(QString::fromUtf8("sliderNMix")); - sizePolicy.setHeightForWidth(sliderNMix->sizePolicy().hasHeightForWidth()); - sliderNMix->setSizePolicy(sizePolicy); - sliderNMix->setValue(0); - sliderNMix->setOrientation(Qt::Horizontal); - - horizontalLayout_8->addWidget(sliderNMix); - - doubleSpinBoxNMix = new QDoubleSpinBox(controlTab); - doubleSpinBoxNMix->setObjectName(QString::fromUtf8("doubleSpinBoxNMix")); - sizePolicy1.setHeightForWidth(doubleSpinBoxNMix->sizePolicy().hasHeightForWidth()); - doubleSpinBoxNMix->setSizePolicy(sizePolicy1); - doubleSpinBoxNMix->setMaximum(1); - doubleSpinBoxNMix->setSingleStep(0.01); - doubleSpinBoxNMix->setValue(0); - - horizontalLayout_8->addWidget(doubleSpinBoxNMix); - - - verticalLayout_3->addLayout(horizontalLayout_8); - - horizontalLayout_9 = new QHBoxLayout(); - horizontalLayout_9->setObjectName(QString::fromUtf8("horizontalLayout_9")); - label_22 = new QLabel(controlTab); - label_22->setObjectName(QString::fromUtf8("label_22")); - label_22->setFont(font2); - - horizontalLayout_9->addWidget(label_22); - - sliderTargetMix = new QSlider(controlTab); - sliderTargetMix->setObjectName(QString::fromUtf8("sliderTargetMix")); - sizePolicy.setHeightForWidth(sliderTargetMix->sizePolicy().hasHeightForWidth()); - sliderTargetMix->setSizePolicy(sizePolicy); - sliderTargetMix->setValue(0); - sliderTargetMix->setSliderPosition(0); - sliderTargetMix->setOrientation(Qt::Horizontal); - - horizontalLayout_9->addWidget(sliderTargetMix); - - doubleSpinBoxTargetMix = new QDoubleSpinBox(controlTab); - doubleSpinBoxTargetMix->setObjectName(QString::fromUtf8("doubleSpinBoxTargetMix")); - sizePolicy1.setHeightForWidth(doubleSpinBoxTargetMix->sizePolicy().hasHeightForWidth()); - doubleSpinBoxTargetMix->setSizePolicy(sizePolicy1); - doubleSpinBoxTargetMix->setMaximum(1); - doubleSpinBoxTargetMix->setSingleStep(0.01); - doubleSpinBoxTargetMix->setValue(0); - - horizontalLayout_9->addWidget(doubleSpinBoxTargetMix); - - - verticalLayout_3->addLayout(horizontalLayout_9); - horizontalLayout_5->addLayout(verticalLayout_3); @@ -742,6 +666,104 @@ public: verticalLayout_6->addWidget(pushButtonGenerateTarget); + label_23 = new QLabel(controlTab); + label_23->setObjectName(QString::fromUtf8("label_23")); + label_23->setFont(font1); + + verticalLayout_6->addWidget(label_23); + + horizontalLayout_22 = new QHBoxLayout(); + horizontalLayout_22->setObjectName(QString::fromUtf8("horizontalLayout_22")); + label_31 = new QLabel(controlTab); + label_31->setObjectName(QString::fromUtf8("label_31")); + label_31->setFont(font2); + + horizontalLayout_22->addWidget(label_31); + + sliderAutotune = new QSlider(controlTab); + sliderAutotune->setObjectName(QString::fromUtf8("sliderAutotune")); + sizePolicy.setHeightForWidth(sliderAutotune->sizePolicy().hasHeightForWidth()); + sliderAutotune->setSizePolicy(sizePolicy); + sliderAutotune->setValue(0); + sliderAutotune->setSliderPosition(0); + sliderAutotune->setOrientation(Qt::Horizontal); + + horizontalLayout_22->addWidget(sliderAutotune); + + doubleSpinBoxAutotune = new QDoubleSpinBox(controlTab); + doubleSpinBoxAutotune->setObjectName(QString::fromUtf8("doubleSpinBoxAutotune")); + sizePolicy1.setHeightForWidth(doubleSpinBoxAutotune->sizePolicy().hasHeightForWidth()); + doubleSpinBoxAutotune->setSizePolicy(sizePolicy1); + doubleSpinBoxAutotune->setMaximum(1); + doubleSpinBoxAutotune->setSingleStep(0.01); + doubleSpinBoxAutotune->setValue(0); + + horizontalLayout_22->addWidget(doubleSpinBoxAutotune); + + + verticalLayout_6->addLayout(horizontalLayout_22); + + horizontalLayout_8 = new QHBoxLayout(); + horizontalLayout_8->setObjectName(QString::fromUtf8("horizontalLayout_8")); + label_21 = new QLabel(controlTab); + label_21->setObjectName(QString::fromUtf8("label_21")); + label_21->setFont(font2); + + horizontalLayout_8->addWidget(label_21); + + sliderNMix = new QSlider(controlTab); + sliderNMix->setObjectName(QString::fromUtf8("sliderNMix")); + sizePolicy.setHeightForWidth(sliderNMix->sizePolicy().hasHeightForWidth()); + sliderNMix->setSizePolicy(sizePolicy); + sliderNMix->setValue(0); + sliderNMix->setOrientation(Qt::Horizontal); + + horizontalLayout_8->addWidget(sliderNMix); + + doubleSpinBoxNMix = new QDoubleSpinBox(controlTab); + doubleSpinBoxNMix->setObjectName(QString::fromUtf8("doubleSpinBoxNMix")); + sizePolicy1.setHeightForWidth(doubleSpinBoxNMix->sizePolicy().hasHeightForWidth()); + doubleSpinBoxNMix->setSizePolicy(sizePolicy1); + doubleSpinBoxNMix->setMaximum(1); + doubleSpinBoxNMix->setSingleStep(0.01); + doubleSpinBoxNMix->setValue(0); + + horizontalLayout_8->addWidget(doubleSpinBoxNMix); + + + verticalLayout_6->addLayout(horizontalLayout_8); + + horizontalLayout_9 = new QHBoxLayout(); + horizontalLayout_9->setObjectName(QString::fromUtf8("horizontalLayout_9")); + label_22 = new QLabel(controlTab); + label_22->setObjectName(QString::fromUtf8("label_22")); + label_22->setFont(font2); + + horizontalLayout_9->addWidget(label_22); + + sliderTargetMix = new QSlider(controlTab); + sliderTargetMix->setObjectName(QString::fromUtf8("sliderTargetMix")); + sizePolicy.setHeightForWidth(sliderTargetMix->sizePolicy().hasHeightForWidth()); + sliderTargetMix->setSizePolicy(sizePolicy); + sliderTargetMix->setValue(0); + sliderTargetMix->setSliderPosition(0); + sliderTargetMix->setOrientation(Qt::Horizontal); + + horizontalLayout_9->addWidget(sliderTargetMix); + + doubleSpinBoxTargetMix = new QDoubleSpinBox(controlTab); + doubleSpinBoxTargetMix->setObjectName(QString::fromUtf8("doubleSpinBoxTargetMix")); + sizePolicy1.setHeightForWidth(doubleSpinBoxTargetMix->sizePolicy().hasHeightForWidth()); + doubleSpinBoxTargetMix->setSizePolicy(sizePolicy1); + doubleSpinBoxTargetMix->setMaximum(1); + doubleSpinBoxTargetMix->setSingleStep(0.01); + doubleSpinBoxTargetMix->setValue(0); + + horizontalLayout_9->addWidget(doubleSpinBoxTargetMix); + + + verticalLayout_6->addLayout(horizontalLayout_9); + verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); verticalLayout_6->addItem(verticalSpacer); @@ -749,13 +771,41 @@ public: horizontalLayout_5->addLayout(verticalLayout_6); - verticalLayout_2 = new QVBoxLayout(); - verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2")); + verticalLayout = new QVBoxLayout(); + verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); label_3 = new QLabel(controlTab); label_3->setObjectName(QString::fromUtf8("label_3")); label_3->setFont(font1); - verticalLayout_2->addWidget(label_3); + verticalLayout->addWidget(label_3); + + listWidgetSounds = new QListWidget(controlTab); + listWidgetSounds->setObjectName(QString::fromUtf8("listWidgetSounds")); + + verticalLayout->addWidget(listWidgetSounds); + + horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2")); + pushButtonLoadSound = new QPushButton(controlTab); + pushButtonLoadSound->setObjectName(QString::fromUtf8("pushButtonLoadSound")); + pushButtonLoadSound->setFont(font); + + horizontalLayout_2->addWidget(pushButtonLoadSound); + + pushButtonDeleteSound = new QPushButton(controlTab); + pushButtonDeleteSound->setObjectName(QString::fromUtf8("pushButtonDeleteSound")); + pushButtonDeleteSound->setFont(font); + + horizontalLayout_2->addWidget(pushButtonDeleteSound); + + + verticalLayout->addLayout(horizontalLayout_2); + + pushButtonClearBrain = new QPushButton(controlTab); + pushButtonClearBrain->setObjectName(QString::fromUtf8("pushButtonClearBrain")); + pushButtonClearBrain->setFont(font); + + verticalLayout->addWidget(pushButtonClearBrain); horizontalLayout_4 = new QHBoxLayout(); horizontalLayout_4->setObjectName(QString::fromUtf8("horizontalLayout_4")); @@ -773,7 +823,7 @@ public: horizontalLayout_4->addWidget(spinBoxBlockSize); - verticalLayout_2->addLayout(horizontalLayout_4); + verticalLayout->addLayout(horizontalLayout_4); horizontalLayout_6 = new QHBoxLayout(); horizontalLayout_6->setObjectName(QString::fromUtf8("horizontalLayout_6")); @@ -792,24 +842,24 @@ public: horizontalLayout_6->addWidget(doubleSpinBoxBlockOverlap); - verticalLayout_2->addLayout(horizontalLayout_6); + verticalLayout->addLayout(horizontalLayout_6); gridLayout = new QGridLayout(); gridLayout->setObjectName(QString::fromUtf8("gridLayout")); - radioButton_gaussian = new QRadioButton(controlTab); + radioButton_hamming = new QRadioButton(controlTab); buttonGroup = new QButtonGroup(MainWindow); buttonGroup->setObjectName(QString::fromUtf8("buttonGroup")); - buttonGroup->addButton(radioButton_gaussian); - radioButton_gaussian->setObjectName(QString::fromUtf8("radioButton_gaussian")); - - gridLayout->addWidget(radioButton_gaussian, 3, 1, 1, 1); - - radioButton_hamming = new QRadioButton(controlTab); buttonGroup->addButton(radioButton_hamming); radioButton_hamming->setObjectName(QString::fromUtf8("radioButton_hamming")); gridLayout->addWidget(radioButton_hamming, 4, 1, 1, 1); + radioButton_gaussian = new QRadioButton(controlTab); + buttonGroup->addButton(radioButton_gaussian); + radioButton_gaussian->setObjectName(QString::fromUtf8("radioButton_gaussian")); + + gridLayout->addWidget(radioButton_gaussian, 3, 1, 1, 1); + radioButton_dodgy = new QRadioButton(controlTab); buttonGroup->addButton(radioButton_dodgy); radioButton_dodgy->setObjectName(QString::fromUtf8("radioButton_dodgy")); @@ -853,13 +903,13 @@ public: gridLayout->addWidget(label_4, 2, 0, 1, 1); - verticalLayout_2->addLayout(gridLayout); + verticalLayout->addLayout(gridLayout); pushButtonGenerate = new QPushButton(controlTab); pushButtonGenerate->setObjectName(QString::fromUtf8("pushButtonGenerate")); pushButtonGenerate->setFont(font); - verticalLayout_2->addWidget(pushButtonGenerate); + verticalLayout->addWidget(pushButtonGenerate); horizontalLayout_7 = new QHBoxLayout(); horizontalLayout_7->setObjectName(QString::fromUtf8("horizontalLayout_7")); @@ -876,50 +926,7 @@ public: horizontalLayout_7->addWidget(pushButtonSaveBrain); - verticalLayout_2->addLayout(horizontalLayout_7); - - verticalSpacer_2 = new QSpacerItem(20, 508, QSizePolicy::Minimum, QSizePolicy::Expanding); - - verticalLayout_2->addItem(verticalSpacer_2); - - - horizontalLayout_5->addLayout(verticalLayout_2); - - verticalLayout = new QVBoxLayout(); - verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); - label_5 = new QLabel(controlTab); - label_5->setObjectName(QString::fromUtf8("label_5")); - label_5->setFont(font); - - verticalLayout->addWidget(label_5); - - listWidgetSounds = new QListWidget(controlTab); - listWidgetSounds->setObjectName(QString::fromUtf8("listWidgetSounds")); - - verticalLayout->addWidget(listWidgetSounds); - - horizontalLayout_2 = new QHBoxLayout(); - horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2")); - pushButtonLoadSound = new QPushButton(controlTab); - pushButtonLoadSound->setObjectName(QString::fromUtf8("pushButtonLoadSound")); - pushButtonLoadSound->setFont(font); - - horizontalLayout_2->addWidget(pushButtonLoadSound); - - pushButtonDeleteSound = new QPushButton(controlTab); - pushButtonDeleteSound->setObjectName(QString::fromUtf8("pushButtonDeleteSound")); - pushButtonDeleteSound->setFont(font); - - horizontalLayout_2->addWidget(pushButtonDeleteSound); - - pushButtonClearBrain = new QPushButton(controlTab); - pushButtonClearBrain->setObjectName(QString::fromUtf8("pushButtonClearBrain")); - pushButtonClearBrain->setFont(font); - - horizontalLayout_2->addWidget(pushButtonClearBrain); - - - verticalLayout->addLayout(horizontalLayout_2); + verticalLayout->addLayout(horizontalLayout_7); horizontalLayout_5->addLayout(verticalLayout); @@ -1070,6 +1077,8 @@ public: QObject::connect(sliderSlideError, SIGNAL(valueChanged(int)), MainWindow, SLOT(slide_error(int))); QObject::connect(doubleSpinBoxStickyness, SIGNAL(valueChanged(double)), MainWindow, SLOT(stickyness_slot(double))); QObject::connect(sliderStickyness, SIGNAL(valueChanged(int)), MainWindow, SLOT(stickyness_slot(int))); + QObject::connect(doubleSpinBoxAutotune, SIGNAL(valueChanged(double)), MainWindow, SLOT(autotune(double))); + QObject::connect(sliderAutotune, SIGNAL(sliderMoved(int)), MainWindow, SLOT(autotune(int))); tabWidget->setCurrentIndex(0); @@ -1079,13 +1088,13 @@ public: void retranslateUi(QMainWindow *MainWindow) { - MainWindow->setWindowTitle(QApplication::translate("MainWindow", "samplebrain 0.10", 0, QApplication::UnicodeUTF8)); + MainWindow->setWindowTitle(QApplication::translate("MainWindow", "samplebrain 0.11", 0, QApplication::UnicodeUTF8)); label_19->setText(QApplication::translate("MainWindow", "brain tweaks", 0, QApplication::UnicodeUTF8)); label_6->setText(QApplication::translate("MainWindow", "fft / mfcc", 0, QApplication::UnicodeUTF8)); #ifndef QT_NO_TOOLTIP sliderRatio->setToolTip(QApplication::translate("MainWindow", "plain fft match vs mfcc values ", 0, QApplication::UnicodeUTF8)); #endif // QT_NO_TOOLTIP - label_20->setText(QApplication::translate("MainWindow", "freq & dynamics / freq only", 0, QApplication::UnicodeUTF8)); + label_20->setText(QApplication::translate("MainWindow", "dynamics / freq", 0, QApplication::UnicodeUTF8)); #ifndef QT_NO_TOOLTIP sliderNRatio->setToolTip(QApplication::translate("MainWindow", "match original or normalised blocks", 0, QApplication::UnicodeUTF8)); #endif // QT_NO_TOOLTIP @@ -1120,7 +1129,7 @@ public: #endif // QT_NO_TOOLTIP label_30->setText(QApplication::translate("MainWindow", "stickyness", 0, QApplication::UnicodeUTF8)); #ifndef QT_NO_TOOLTIP - sliderStickyness->setToolTip(QApplication::translate("MainWindow", "how long it takes for the novelty to wear off", 0, QApplication::UnicodeUTF8)); + sliderStickyness->setToolTip(QApplication::translate("MainWindow", "prioritise brain order over closeness", 0, QApplication::UnicodeUTF8)); #endif // QT_NO_TOOLTIP #ifndef QT_NO_TOOLTIP label_28->setToolTip(QString()); @@ -1140,7 +1149,7 @@ public: #ifndef QT_NO_TOOLTIP radioButtonAlgoRevBasic->setToolTip(QApplication::translate("MainWindow", "full brain reverse search", 0, QApplication::UnicodeUTF8)); #endif // QT_NO_TOOLTIP - radioButtonAlgoRevBasic->setText(QApplication::translate("MainWindow", "rev basic", 0, QApplication::UnicodeUTF8)); + radioButtonAlgoRevBasic->setText(QApplication::translate("MainWindow", "rev", 0, QApplication::UnicodeUTF8)); #ifndef QT_NO_TOOLTIP radioButtonSynaptic->setToolTip(QApplication::translate("MainWindow", "search based on synapse connections", 0, QApplication::UnicodeUTF8)); #endif // QT_NO_TOOLTIP @@ -1168,15 +1177,6 @@ public: #endif // QT_NO_TOOLTIP #ifndef QT_NO_TOOLTIP spinBoxSlideError->setToolTip(QApplication::translate("MainWindow", "how many connections to search (ordered in closeness)", 0, QApplication::UnicodeUTF8)); -#endif // QT_NO_TOOLTIP - label_23->setText(QApplication::translate("MainWindow", "mix", 0, QApplication::UnicodeUTF8)); - label_21->setText(QApplication::translate("MainWindow", "dynamic / normalised ", 0, QApplication::UnicodeUTF8)); -#ifndef QT_NO_TOOLTIP - sliderNMix->setToolTip(QApplication::translate("MainWindow", "mix in the normalised blocks", 0, QApplication::UnicodeUTF8)); -#endif // QT_NO_TOOLTIP - label_22->setText(QApplication::translate("MainWindow", "brain / target", 0, QApplication::UnicodeUTF8)); -#ifndef QT_NO_TOOLTIP - sliderTargetMix->setToolTip(QApplication::translate("MainWindow", "mix in the original blocks", 0, QApplication::UnicodeUTF8)); #endif // QT_NO_TOOLTIP label_16->setText(QApplication::translate("MainWindow", "target sound", 0, QApplication::UnicodeUTF8)); pushButtonLoadTarget->setText(QApplication::translate("MainWindow", "load target", 0, QApplication::UnicodeUTF8)); @@ -1192,11 +1192,27 @@ public: radioButton_rectangleTarget->setText(QApplication::translate("MainWindow", "rectangle", 0, QApplication::UnicodeUTF8)); label_14->setText(QApplication::translate("MainWindow", "window shape", 0, QApplication::UnicodeUTF8)); pushButtonGenerateTarget->setText(QApplication::translate("MainWindow", "(re)generate blocks", 0, QApplication::UnicodeUTF8)); - label_3->setText(QApplication::translate("MainWindow", "brain parameters", 0, QApplication::UnicodeUTF8)); + label_23->setText(QApplication::translate("MainWindow", "mix", 0, QApplication::UnicodeUTF8)); + label_31->setText(QApplication::translate("MainWindow", "autotune", 0, QApplication::UnicodeUTF8)); +#ifndef QT_NO_TOOLTIP + sliderAutotune->setToolTip(QApplication::translate("MainWindow", "amount to match the frequency", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + label_21->setText(QApplication::translate("MainWindow", "dynamic / normalised ", 0, QApplication::UnicodeUTF8)); +#ifndef QT_NO_TOOLTIP + sliderNMix->setToolTip(QApplication::translate("MainWindow", "mix in the normalised blocks", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + label_22->setText(QApplication::translate("MainWindow", "brain / target", 0, QApplication::UnicodeUTF8)); +#ifndef QT_NO_TOOLTIP + sliderTargetMix->setToolTip(QApplication::translate("MainWindow", "mix in the original blocks", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + label_3->setText(QApplication::translate("MainWindow", "brain contents", 0, QApplication::UnicodeUTF8)); + pushButtonLoadSound->setText(QApplication::translate("MainWindow", "load sound", 0, QApplication::UnicodeUTF8)); + pushButtonDeleteSound->setText(QApplication::translate("MainWindow", "delete selected", 0, QApplication::UnicodeUTF8)); + pushButtonClearBrain->setText(QApplication::translate("MainWindow", "clear brain", 0, QApplication::UnicodeUTF8)); label->setText(QApplication::translate("MainWindow", "block size", 0, QApplication::UnicodeUTF8)); label_2->setText(QApplication::translate("MainWindow", "block overlap", 0, QApplication::UnicodeUTF8)); - radioButton_gaussian->setText(QApplication::translate("MainWindow", "gaussian", 0, QApplication::UnicodeUTF8)); radioButton_hamming->setText(QApplication::translate("MainWindow", "hamming", 0, QApplication::UnicodeUTF8)); + radioButton_gaussian->setText(QApplication::translate("MainWindow", "gaussian", 0, QApplication::UnicodeUTF8)); radioButton_dodgy->setText(QApplication::translate("MainWindow", "dodgy", 0, QApplication::UnicodeUTF8)); radioButton_blackman->setText(QApplication::translate("MainWindow", "blackman", 0, QApplication::UnicodeUTF8)); radioButton_rectagle->setText(QApplication::translate("MainWindow", "rectangle", 0, QApplication::UnicodeUTF8)); @@ -1207,10 +1223,6 @@ public: pushButtonGenerate->setText(QApplication::translate("MainWindow", "(re)generate brain", 0, QApplication::UnicodeUTF8)); pushButtonLoadBrain->setText(QApplication::translate("MainWindow", "load brain", 0, QApplication::UnicodeUTF8)); pushButtonSaveBrain->setText(QApplication::translate("MainWindow", "save brain", 0, QApplication::UnicodeUTF8)); - label_5->setText(QApplication::translate("MainWindow", "brain contents", 0, QApplication::UnicodeUTF8)); - pushButtonLoadSound->setText(QApplication::translate("MainWindow", "load sound", 0, QApplication::UnicodeUTF8)); - pushButtonDeleteSound->setText(QApplication::translate("MainWindow", "delete selected", 0, QApplication::UnicodeUTF8)); - pushButtonClearBrain->setText(QApplication::translate("MainWindow", "clear brain", 0, QApplication::UnicodeUTF8)); tabWidget->setTabText(tabWidget->indexOf(controlTab), QApplication::translate("MainWindow", "search", 0, QApplication::UnicodeUTF8)); tabWidget->setTabText(tabWidget->indexOf(logTab), QApplication::translate("MainWindow", "log", 0, QApplication::UnicodeUTF8)); pushButtonPlay->setText(QString()); @@ -1228,4 +1240,4 @@ namespace Ui { QT_END_NAMESPACE -#endif // SAMPLEBRAINJ11878_H +#endif // SAMPLEBRAINPM4153_H diff --git a/samplebrain/qt/qtmain.cpp b/samplebrain/qt/qtmain.cpp index 5a27f90..df570ec 100644 --- a/samplebrain/qt/qtmain.cpp +++ b/samplebrain/qt/qtmain.cpp @@ -23,7 +23,7 @@ #include "process_thread.h" #include "audio_thread.h" -#include "pitchshift.h" +//#include "pitchshift.h" using namespace std; @@ -32,7 +32,7 @@ int main( int argc , char *argv[] ){ MainWindow mainWin; mainWin.show(); - pitchshift::init(44100); + //pitchshift::init(44100); process_thread pt; audio_thread at(pt); diff --git a/samplebrain/qt/samplebrain.pro b/samplebrain/qt/samplebrain.pro index fa10264..ba3cbe9 100644 --- a/samplebrain/qt/samplebrain.pro +++ b/samplebrain/qt/samplebrain.pro @@ -25,7 +25,6 @@ SOURCES += MainWindow.cpp \ ../src/renderer.cpp \ ../src/status.cpp \ ../src/window.cpp \ - ../src/pitchshift.cpp \ ../src/aquila/filter/MelFilterBank.cpp \ ../src/aquila/filter/MelFilter.cpp \ ../src/aquila/transform/Dct.cpp \ @@ -39,7 +38,7 @@ SOURCES += MainWindow.cpp \ ../../../jellyfish/src/core/stream.cpp INCLUDEPATH += ../src -LIBS += -L.. -lrubberband -lportaudio -lfftw3 -lsndfile -llo -ldl -lpthread -lm +LIBS += -L.. -lportaudio -lfftw3 -lsndfile -llo -ldl -lpthread -lm #CONFIG+=debug QMAKE_CXXFLAGS += -Wall -Wno-unused -std=c++11 -DDONT_USE_FLUXA_GRAPH diff --git a/samplebrain/src/fft.cpp b/samplebrain/src/fft.cpp index f83930d..5866e0d 100644 --- a/samplebrain/src/fft.cpp +++ b/samplebrain/src/fft.cpp @@ -65,7 +65,9 @@ float FFT::calculate_dominant_freq() { highest=t; } } - return index * (SRATE/(float)m_length); + float freq = index * (SRATE/(float)m_length); + if (freq<0.01) freq=0.01; + return freq; } void FFT::calculate_bins() { diff --git a/samplebrain/src/renderer.cpp b/samplebrain/src/renderer.cpp index bad3688..627afb2 100644 --- a/samplebrain/src/renderer.cpp +++ b/samplebrain/src/renderer.cpp @@ -16,7 +16,7 @@ #include "renderer.h" #include -#include "pitchshift.h" +//#include "pitchshift.h" using namespace spiralcore; using namespace std; @@ -157,14 +157,17 @@ void renderer::render(u32 nframes, float *buf) { // get the sample offset into the buffer s32 offset = i->m_time-m_render_time; + u32 block_length = pcm.get_length(); // assume midway through block u32 block_start = offset; u32 buffer_start = 0; if (offset<0) { block_start=-offset; - if (block_start>=pcm.get_length() || - i->m_position>=pcm.get_length()) i->m_finished=true; + if (block_start>=block_length && + i->m_position>=block_length) { + i->m_finished=true; + } } else { // block is midway through buffer block_start=0; buffer_start=offset; @@ -174,35 +177,54 @@ void renderer::render(u32 nframes, float *buf) { // cerr<<"block start:"<m_tgt_index).get_freq() / - m_source.get_block(i->m_index).get_freq(); // fade in/out autotune - pitch_scale = pitch_scale*m_autotune + 1.0f*(1-m_autotune); + //pitch_scale = pitch_scale*m_autotune + 1.0f*(1-m_autotune); + + float pitch_scale = 1; + + if (m_autotune>0) { + pitch_scale = m_target.get_block(i->m_tgt_index).get_freq() / + m_source.get_block(i->m_index).get_freq(); + float max = 1+(m_autotune*m_autotune)*100.0f; + if (pitch_scale>(max)) pitch_scale=max; + if (pitch_scale<(1/max)) pitch_scale=1/max; + } //pitchshift::process(pcm,pitch_scale,render_pcm); - if (!i->m_finished) { // mix in u32 buffer_pos = buffer_start; u32 block_pos = block_start; u32 block_end = pcm.get_length(); + while (i->m_positionm_position]*(1-m_n_mix)+ - n_pcm[block_pos]*m_n_mix); + n_pcm[i->m_position]*m_n_mix); - // for mixing with target audio - float target_sample = target_pcm[block_pos]; + float target_sample = 0; + + // if playback scale is lower than target then we may + // run off the end of the target block + if (block_posm_position+=pitch_scale; + // repeat fast blocks if we are still playing the source + if (block_posm_position>block_end) { + i->m_position=0; + } + ++buffer_pos; ++block_pos; } diff --git a/samplebrain/src/renderer.h b/samplebrain/src/renderer.h index 5911747..8091a41 100644 --- a/samplebrain/src/renderer.h +++ b/samplebrain/src/renderer.h @@ -52,6 +52,7 @@ namespace spiralcore { void set_target_mix(float s) { m_target_mix=s; } void set_slide_error(double s) { m_slide_error=s; } void set_stretch(u32 s) { m_stretch=s; } + void set_autotune(float s) { m_autotune=s; } search_params *get_params() { return &m_search_params; } brain &get_source() { return m_source; }