mirror of
https://gitlab.com/then-try-this/samplebrain.git
synced 2025-05-12 10:37:20 +00:00
started work on live input
This commit is contained in:
parent
b146f869c8
commit
3deaf9ac1e
@ -7,11 +7,11 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>910</width>
|
<width>910</width>
|
||||||
<height>669</height>
|
<height>671</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>samplebrain 0.16</string>
|
<string>samplebrain 0.17</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">
|
||||||
@ -865,6 +865,18 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="mic">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Comic Sans MS</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>use mic input</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_23">
|
<widget class="QLabel" name="label_23">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
@ -1384,7 +1396,24 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_15">
|
<layout class="QHBoxLayout" name="horizontalLayout_15">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="netContainer"/>
|
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="netContainer"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>This program is free software made in Cornwall by <a href="http://fo.am/kernow">FoAM Kernow</a></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
@ -2407,6 +2436,22 @@
|
|||||||
</hint>
|
</hint>
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>mic</sender>
|
||||||
|
<signal>clicked(bool)</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>mic(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>404</x>
|
||||||
|
<y>601</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>454</x>
|
||||||
|
<y>335</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
</connections>
|
</connections>
|
||||||
<slots>
|
<slots>
|
||||||
<slot>play_slot()</slot>
|
<slot>play_slot()</slot>
|
||||||
@ -2463,5 +2508,6 @@
|
|||||||
<slot>load_sounds()</slot>
|
<slot>load_sounds()</slot>
|
||||||
<slot>select_all()</slot>
|
<slot>select_all()</slot>
|
||||||
<slot>select_none()</slot>
|
<slot>select_none()</slot>
|
||||||
|
<slot>mic(bool)</slot>
|
||||||
</slots>
|
</slots>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -239,6 +239,7 @@ private slots:
|
|||||||
|
|
||||||
void brain_shape(int n) { send_process_osc("/window_type","i",n); }
|
void brain_shape(int n) { send_process_osc("/window_type","i",n); }
|
||||||
void target_shape(int n) { send_process_osc("/target_window_type","i",n); }
|
void target_shape(int n) { send_process_osc("/target_window_type","i",n); }
|
||||||
|
void mic(bool n) { send_audio_osc("/mic","i",(int)n); }
|
||||||
|
|
||||||
void record() {
|
void record() {
|
||||||
if (m_save_wav=="") {
|
if (m_save_wav=="") {
|
||||||
|
@ -25,12 +25,14 @@ audio_thread::audio_thread(process_thread &p) :
|
|||||||
m_osc("8888"),
|
m_osc("8888"),
|
||||||
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)
|
||||||
{
|
{
|
||||||
start_audio();
|
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();
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
m_osc.run();
|
m_osc.run();
|
||||||
}
|
}
|
||||||
@ -54,13 +56,15 @@ void audio_thread::run_audio(void* c, unsigned int frames) {
|
|||||||
if (state) {
|
if (state) {
|
||||||
audio_thread *at = (audio_thread*)c;
|
audio_thread *at = (audio_thread*)c;
|
||||||
at->m_audio_device->left_out.zero();
|
at->m_audio_device->left_out.zero();
|
||||||
at->process(at->m_audio_device->left_out,
|
at->process(at->m_audio_device->left_in,
|
||||||
|
at->m_audio_device->right_in,
|
||||||
|
at->m_audio_device->left_out,
|
||||||
at->m_audio_device->right_out);
|
at->m_audio_device->right_out);
|
||||||
at->m_audio_device->maybe_record();
|
at->m_audio_device->maybe_record();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_thread::process(sample &s, sample &s2) {
|
void audio_thread::process(sample &left_in, sample &right_in, sample &left_out, sample &right_out) {
|
||||||
|
|
||||||
command_ring_buffer::command cmd;
|
command_ring_buffer::command cmd;
|
||||||
while (m_osc.get(cmd)) {
|
while (m_osc.get(cmd)) {
|
||||||
@ -162,16 +166,31 @@ void audio_thread::process(sample &s, sample &s2) {
|
|||||||
m_left_renderer->reset();
|
m_left_renderer->reset();
|
||||||
m_right_renderer->reset();
|
m_right_renderer->reset();
|
||||||
}
|
}
|
||||||
|
if (name=="/mic") {
|
||||||
|
m_mic_mode = cmd.get_int(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.zero();
|
left_out.zero();
|
||||||
s2.zero();
|
right_out.zero();
|
||||||
if (!pthread_mutex_trylock(m_brain_mutex)) {
|
if (!pthread_mutex_trylock(m_brain_mutex)) {
|
||||||
m_left_renderer->process(s.get_length(),s.get_non_const_buffer());
|
|
||||||
|
block_stream *bs=NULL;
|
||||||
|
|
||||||
|
if (m_mic_mode) {
|
||||||
|
m_block_stream->process(left_in,right_in);
|
||||||
|
bs = m_block_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_left_renderer->process(left_out.get_length(),
|
||||||
|
left_out.get_non_const_buffer(),
|
||||||
|
bs);
|
||||||
if (m_stereo_mode) {
|
if (m_stereo_mode) {
|
||||||
m_right_renderer->process(s2.get_length(),s2.get_non_const_buffer());
|
m_right_renderer->process(right_out.get_length(),
|
||||||
|
right_out.get_non_const_buffer(),
|
||||||
|
bs);
|
||||||
} else {
|
} else {
|
||||||
s2=s;
|
right_out=left_out;
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
} else {
|
} else {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "jellyfish/OSC_server.h"
|
#include "jellyfish/OSC_server.h"
|
||||||
#include "process_thread.h"
|
#include "process_thread.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
#include "block_stream.h"
|
||||||
#include "jellyfish/audio.h"
|
#include "jellyfish/audio.h"
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -28,13 +29,14 @@ public:
|
|||||||
audio_thread(process_thread &p);
|
audio_thread(process_thread &p);
|
||||||
~audio_thread();
|
~audio_thread();
|
||||||
|
|
||||||
void process(sample &left, sample &right);
|
void process(sample &left_in, sample &right_in, sample &left_out, sample &right_out);
|
||||||
|
|
||||||
static void run_audio(void* c, unsigned int frames);
|
static void run_audio(void* c, unsigned int frames);
|
||||||
audio_device *m_audio_device;
|
audio_device *m_audio_device;
|
||||||
|
|
||||||
renderer *m_left_renderer;
|
renderer *m_left_renderer;
|
||||||
renderer *m_right_renderer;
|
renderer *m_right_renderer;
|
||||||
|
block_stream *m_block_stream;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void start_audio();
|
void start_audio();
|
||||||
@ -43,6 +45,7 @@ private:
|
|||||||
process_thread &m_process_thread;
|
process_thread &m_process_thread;
|
||||||
pthread_mutex_t* m_brain_mutex;
|
pthread_mutex_t* m_brain_mutex;
|
||||||
bool m_stereo_mode;
|
bool m_stereo_mode;
|
||||||
|
bool m_mic_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
** Form generated from reading UI file 'samplebrainr24659.ui'
|
** Form generated from reading UI file 'samplebrainr15646.ui'
|
||||||
**
|
**
|
||||||
** Created by: Qt User Interface Compiler version 4.8.6
|
** Created by: Qt User Interface Compiler version 4.8.6
|
||||||
**
|
**
|
||||||
** WARNING! All changes made in this file will be lost when recompiling UI file!
|
** WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#ifndef SAMPLEBRAINR24659_H
|
#ifndef SAMPLEBRAINR15646_H
|
||||||
#define SAMPLEBRAINR24659_H
|
#define SAMPLEBRAINR15646_H
|
||||||
|
|
||||||
#include <QtCore/QVariant>
|
#include <QtCore/QVariant>
|
||||||
#include <QtGui/QAction>
|
#include <QtGui/QAction>
|
||||||
@ -99,6 +99,7 @@ public:
|
|||||||
QLabel *label_14;
|
QLabel *label_14;
|
||||||
QComboBox *comboBoxTargetShape;
|
QComboBox *comboBoxTargetShape;
|
||||||
QPushButton *pushButtonGenerateTarget;
|
QPushButton *pushButtonGenerateTarget;
|
||||||
|
QCheckBox *mic;
|
||||||
QLabel *label_23;
|
QLabel *label_23;
|
||||||
QHBoxLayout *horizontalLayout_22;
|
QHBoxLayout *horizontalLayout_22;
|
||||||
QLabel *label_31;
|
QLabel *label_31;
|
||||||
@ -143,7 +144,9 @@ public:
|
|||||||
QSpacerItem *verticalSpacer_2;
|
QSpacerItem *verticalSpacer_2;
|
||||||
QWidget *netTab;
|
QWidget *netTab;
|
||||||
QHBoxLayout *horizontalLayout_15;
|
QHBoxLayout *horizontalLayout_15;
|
||||||
|
QVBoxLayout *verticalLayout_7;
|
||||||
QVBoxLayout *netContainer;
|
QVBoxLayout *netContainer;
|
||||||
|
QLabel *label_4;
|
||||||
QHBoxLayout *horizontalLayout_12;
|
QHBoxLayout *horizontalLayout_12;
|
||||||
QPushButton *pushButtonPlay;
|
QPushButton *pushButtonPlay;
|
||||||
QPushButton *pushButtonStop;
|
QPushButton *pushButtonStop;
|
||||||
@ -161,7 +164,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (MainWindow->objectName().isEmpty())
|
if (MainWindow->objectName().isEmpty())
|
||||||
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
|
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
|
||||||
MainWindow->resize(910, 669);
|
MainWindow->resize(910, 671);
|
||||||
centralwidget = new QWidget(MainWindow);
|
centralwidget = new QWidget(MainWindow);
|
||||||
centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
|
centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
|
||||||
verticalLayout_4 = new QVBoxLayout(centralwidget);
|
verticalLayout_4 = new QVBoxLayout(centralwidget);
|
||||||
@ -588,6 +591,14 @@ public:
|
|||||||
|
|
||||||
verticalLayout_6->addWidget(pushButtonGenerateTarget);
|
verticalLayout_6->addWidget(pushButtonGenerateTarget);
|
||||||
|
|
||||||
|
mic = new QCheckBox(controlTab);
|
||||||
|
mic->setObjectName(QString::fromUtf8("mic"));
|
||||||
|
QFont font3;
|
||||||
|
font3.setFamily(QString::fromUtf8("Comic Sans MS"));
|
||||||
|
mic->setFont(font3);
|
||||||
|
|
||||||
|
verticalLayout_6->addWidget(mic);
|
||||||
|
|
||||||
label_23 = new QLabel(controlTab);
|
label_23 = new QLabel(controlTab);
|
||||||
label_23->setObjectName(QString::fromUtf8("label_23"));
|
label_23->setObjectName(QString::fromUtf8("label_23"));
|
||||||
label_23->setFont(font1);
|
label_23->setFont(font1);
|
||||||
@ -852,10 +863,25 @@ public:
|
|||||||
netTab->setObjectName(QString::fromUtf8("netTab"));
|
netTab->setObjectName(QString::fromUtf8("netTab"));
|
||||||
horizontalLayout_15 = new QHBoxLayout(netTab);
|
horizontalLayout_15 = new QHBoxLayout(netTab);
|
||||||
horizontalLayout_15->setObjectName(QString::fromUtf8("horizontalLayout_15"));
|
horizontalLayout_15->setObjectName(QString::fromUtf8("horizontalLayout_15"));
|
||||||
|
verticalLayout_7 = new QVBoxLayout();
|
||||||
|
verticalLayout_7->setObjectName(QString::fromUtf8("verticalLayout_7"));
|
||||||
netContainer = new QVBoxLayout();
|
netContainer = new QVBoxLayout();
|
||||||
netContainer->setObjectName(QString::fromUtf8("netContainer"));
|
netContainer->setObjectName(QString::fromUtf8("netContainer"));
|
||||||
|
|
||||||
horizontalLayout_15->addLayout(netContainer);
|
verticalLayout_7->addLayout(netContainer);
|
||||||
|
|
||||||
|
label_4 = new QLabel(netTab);
|
||||||
|
label_4->setObjectName(QString::fromUtf8("label_4"));
|
||||||
|
QSizePolicy sizePolicy3(QSizePolicy::Preferred, QSizePolicy::Maximum);
|
||||||
|
sizePolicy3.setHorizontalStretch(0);
|
||||||
|
sizePolicy3.setVerticalStretch(0);
|
||||||
|
sizePolicy3.setHeightForWidth(label_4->sizePolicy().hasHeightForWidth());
|
||||||
|
label_4->setSizePolicy(sizePolicy3);
|
||||||
|
|
||||||
|
verticalLayout_7->addWidget(label_4);
|
||||||
|
|
||||||
|
|
||||||
|
horizontalLayout_15->addLayout(verticalLayout_7);
|
||||||
|
|
||||||
tabWidget->addTab(netTab, QString());
|
tabWidget->addTab(netTab, QString());
|
||||||
|
|
||||||
@ -1000,6 +1026,7 @@ public:
|
|||||||
QObject::connect(pushButtonLoadSounds, SIGNAL(released()), MainWindow, SLOT(load_sounds()));
|
QObject::connect(pushButtonLoadSounds, SIGNAL(released()), MainWindow, SLOT(load_sounds()));
|
||||||
QObject::connect(toolButtonAll, SIGNAL(released()), MainWindow, SLOT(select_all()));
|
QObject::connect(toolButtonAll, SIGNAL(released()), MainWindow, SLOT(select_all()));
|
||||||
QObject::connect(toolButtonNone, SIGNAL(released()), MainWindow, SLOT(select_none()));
|
QObject::connect(toolButtonNone, SIGNAL(released()), MainWindow, SLOT(select_none()));
|
||||||
|
QObject::connect(mic, SIGNAL(clicked(bool)), MainWindow, SLOT(mic(bool)));
|
||||||
|
|
||||||
tabWidget->setCurrentIndex(0);
|
tabWidget->setCurrentIndex(0);
|
||||||
|
|
||||||
@ -1009,7 +1036,7 @@ public:
|
|||||||
|
|
||||||
void retranslateUi(QMainWindow *MainWindow)
|
void retranslateUi(QMainWindow *MainWindow)
|
||||||
{
|
{
|
||||||
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "samplebrain 0.16", 0, QApplication::UnicodeUTF8));
|
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "samplebrain 0.17", 0, QApplication::UnicodeUTF8));
|
||||||
label_19->setText(QApplication::translate("MainWindow", "brain tweaks", 0, QApplication::UnicodeUTF8));
|
label_19->setText(QApplication::translate("MainWindow", "brain tweaks", 0, QApplication::UnicodeUTF8));
|
||||||
label_6->setText(QApplication::translate("MainWindow", "fft / mfcc", 0, QApplication::UnicodeUTF8));
|
label_6->setText(QApplication::translate("MainWindow", "fft / mfcc", 0, QApplication::UnicodeUTF8));
|
||||||
#ifndef QT_NO_TOOLTIP
|
#ifndef QT_NO_TOOLTIP
|
||||||
@ -1107,6 +1134,7 @@ public:
|
|||||||
<< QApplication::translate("MainWindow", "rectangle", 0, QApplication::UnicodeUTF8)
|
<< QApplication::translate("MainWindow", "rectangle", 0, QApplication::UnicodeUTF8)
|
||||||
);
|
);
|
||||||
pushButtonGenerateTarget->setText(QApplication::translate("MainWindow", "(re)generate blocks", 0, QApplication::UnicodeUTF8));
|
pushButtonGenerateTarget->setText(QApplication::translate("MainWindow", "(re)generate blocks", 0, QApplication::UnicodeUTF8));
|
||||||
|
mic->setText(QApplication::translate("MainWindow", "use mic input", 0, QApplication::UnicodeUTF8));
|
||||||
label_23->setText(QApplication::translate("MainWindow", "mix", 0, QApplication::UnicodeUTF8));
|
label_23->setText(QApplication::translate("MainWindow", "mix", 0, QApplication::UnicodeUTF8));
|
||||||
label_31->setText(QApplication::translate("MainWindow", "autotune", 0, QApplication::UnicodeUTF8));
|
label_31->setText(QApplication::translate("MainWindow", "autotune", 0, QApplication::UnicodeUTF8));
|
||||||
#ifndef QT_NO_TOOLTIP
|
#ifndef QT_NO_TOOLTIP
|
||||||
@ -1145,6 +1173,7 @@ public:
|
|||||||
pushButtonLoadBrain->setText(QApplication::translate("MainWindow", "load brain", 0, QApplication::UnicodeUTF8));
|
pushButtonLoadBrain->setText(QApplication::translate("MainWindow", "load brain", 0, QApplication::UnicodeUTF8));
|
||||||
pushButtonSaveBrain->setText(QApplication::translate("MainWindow", "save brain", 0, QApplication::UnicodeUTF8));
|
pushButtonSaveBrain->setText(QApplication::translate("MainWindow", "save brain", 0, QApplication::UnicodeUTF8));
|
||||||
tabWidget->setTabText(tabWidget->indexOf(controlTab), QApplication::translate("MainWindow", "search", 0, QApplication::UnicodeUTF8));
|
tabWidget->setTabText(tabWidget->indexOf(controlTab), QApplication::translate("MainWindow", "search", 0, QApplication::UnicodeUTF8));
|
||||||
|
label_4->setText(QApplication::translate("MainWindow", "This program is free software made in Cornwall by <a href=\"http://fo.am/kernow\">FoAM Kernow</a>", 0, QApplication::UnicodeUTF8));
|
||||||
tabWidget->setTabText(tabWidget->indexOf(netTab), QApplication::translate("MainWindow", "net", 0, QApplication::UnicodeUTF8));
|
tabWidget->setTabText(tabWidget->indexOf(netTab), QApplication::translate("MainWindow", "net", 0, QApplication::UnicodeUTF8));
|
||||||
pushButtonPlay->setText(QString());
|
pushButtonPlay->setText(QString());
|
||||||
pushButtonStop->setText(QString());
|
pushButtonStop->setText(QString());
|
||||||
@ -1163,4 +1192,4 @@ namespace Ui {
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // SAMPLEBRAINR24659_H
|
#endif // SAMPLEBRAINR15646_H
|
||||||
|
@ -23,176 +23,181 @@ using namespace spiralcore;
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
static void _process(void *c) {
|
static void _process(void *c) {
|
||||||
process_thread *p=(process_thread*)c;
|
process_thread *p=(process_thread*)c;
|
||||||
p->process();
|
p->process();
|
||||||
}
|
}
|
||||||
|
|
||||||
process_thread::process_thread() :
|
process_thread::process_thread() :
|
||||||
m_osc("8889"),
|
m_osc("8889"),
|
||||||
m_source_block_size(3000),
|
m_source_block_size(3000),
|
||||||
m_source_overlap(0.75),
|
m_source_overlap(0.75),
|
||||||
m_target_block_size(3000),
|
m_target_block_size(3000),
|
||||||
m_target_overlap(0.75),
|
m_target_overlap(0.75),
|
||||||
m_window_type(window::DODGY),
|
m_window_type(window::DODGY),
|
||||||
m_target_window_type(window::DODGY)
|
m_target_window_type(window::DODGY)
|
||||||
{
|
{
|
||||||
m_brain_mutex = new pthread_mutex_t;
|
m_brain_mutex = new pthread_mutex_t;
|
||||||
pthread_mutex_init(m_brain_mutex,NULL);
|
pthread_mutex_init(m_brain_mutex,NULL);
|
||||||
m_osc.run();
|
m_osc.run();
|
||||||
|
|
||||||
// start the processing thread
|
// start the processing thread
|
||||||
m_thread = new pthread_t;
|
m_thread = new pthread_t;
|
||||||
pthread_create(m_thread,NULL,(void*(*)(void*))_process,this);
|
pthread_create(m_thread,NULL,(void*(*)(void*))_process,this);
|
||||||
}
|
}
|
||||||
|
|
||||||
process_thread::~process_thread() {
|
process_thread::~process_thread() {
|
||||||
pthread_cancel(*m_thread);
|
pthread_cancel(*m_thread);
|
||||||
delete m_brain_mutex;
|
delete m_brain_mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_thread::process() {
|
void process_thread::process() {
|
||||||
command_ring_buffer::command cmd;
|
command_ring_buffer::command cmd;
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
while (m_osc.get(cmd)) {
|
while (m_osc.get(cmd)) {
|
||||||
string name = cmd.m_name;
|
string name = cmd.m_name;
|
||||||
//cerr<<name<<endl;
|
//cerr<<name<<endl;
|
||||||
if (name=="/load_sample") {
|
if (name=="/load_sample") {
|
||||||
pthread_mutex_lock(m_brain_mutex);
|
pthread_mutex_lock(m_brain_mutex);
|
||||||
m_source.load_sound(cmd.get_string(0),brain::MIX);
|
m_source.load_sound(cmd.get_string(0),brain::MIX);
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
}
|
}
|
||||||
if (name=="/delete_sample") {
|
if (name=="/delete_sample") {
|
||||||
pthread_mutex_lock(m_brain_mutex);
|
pthread_mutex_lock(m_brain_mutex);
|
||||||
m_source.delete_sound(cmd.get_string(0));
|
m_source.delete_sound(cmd.get_string(0));
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
}
|
}
|
||||||
if (name=="/activate_sound") {
|
if (name=="/activate_sound") {
|
||||||
pthread_mutex_lock(m_brain_mutex);
|
pthread_mutex_lock(m_brain_mutex);
|
||||||
m_source.activate_sound(cmd.get_string(0),1);
|
m_source.activate_sound(cmd.get_string(0),1);
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
}
|
}
|
||||||
if (name=="/deactivate_sound") {
|
if (name=="/deactivate_sound") {
|
||||||
pthread_mutex_lock(m_brain_mutex);
|
pthread_mutex_lock(m_brain_mutex);
|
||||||
m_source.activate_sound(cmd.get_string(0),0);
|
m_source.activate_sound(cmd.get_string(0),0);
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
}
|
}
|
||||||
if (name=="/source_block_size") {
|
if (name=="/source_block_size") {
|
||||||
m_source_block_size = cmd.get_int(0);
|
m_source_block_size = cmd.get_int(0);
|
||||||
}
|
}
|
||||||
if (name=="/source_overlap") {
|
if (name=="/source_overlap") {
|
||||||
m_source_overlap = m_source_block_size*cmd.get_float(0);
|
m_source_overlap = m_source_block_size*cmd.get_float(0);
|
||||||
}
|
}
|
||||||
if (name=="/generate_brain") {
|
if (name=="/generate_brain") {
|
||||||
pthread_mutex_lock(m_brain_mutex);
|
pthread_mutex_lock(m_brain_mutex);
|
||||||
m_source.init(m_source_block_size, m_source_overlap, m_window_type);
|
m_source.init(m_source_block_size, m_source_overlap, m_window_type);
|
||||||
search_params p(1,0,0,100,0);
|
search_params p(1,0,0,100,0);
|
||||||
m_source.build_synapses_fixed(p);
|
m_source.build_synapses_fixed(p);
|
||||||
m_left_renderer->reset();
|
m_left_renderer->reset();
|
||||||
m_right_renderer->reset();
|
m_right_renderer->reset();
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
}
|
}
|
||||||
if (name=="/load_target") {
|
if (name=="/load_target") {
|
||||||
pthread_mutex_lock(m_brain_mutex);
|
pthread_mutex_lock(m_brain_mutex);
|
||||||
m_left_target.clear_sounds();
|
m_left_target.clear_sounds();
|
||||||
m_left_target.load_sound(cmd.get_string(0),brain::LEFT);
|
m_left_target.load_sound(cmd.get_string(0),brain::LEFT);
|
||||||
m_right_target.clear_sounds();
|
m_right_target.clear_sounds();
|
||||||
m_right_target.load_sound(cmd.get_string(0),brain::RIGHT);
|
m_right_target.load_sound(cmd.get_string(0),brain::RIGHT);
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
}
|
}
|
||||||
if (name=="/target_block_size") {
|
if (name=="/target_block_size") {
|
||||||
m_target_block_size = cmd.get_int(0);
|
m_target_block_size = cmd.get_int(0);
|
||||||
}
|
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
|
||||||
if (name=="/target_overlap") {
|
}
|
||||||
m_target_overlap = m_target_block_size*cmd.get_float(0);
|
if (name=="/target_overlap") {
|
||||||
}
|
m_target_overlap = m_target_block_size*cmd.get_float(0);
|
||||||
if (name=="/generate_target") {
|
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
|
||||||
pthread_mutex_lock(m_brain_mutex);
|
}
|
||||||
m_left_target.init(m_target_block_size, m_target_overlap, m_target_window_type);
|
if (name=="/generate_target") {
|
||||||
m_right_target.init(m_target_block_size, m_target_overlap, m_target_window_type);
|
pthread_mutex_lock(m_brain_mutex);
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
m_left_target.init(m_target_block_size, m_target_overlap, m_target_window_type);
|
||||||
}
|
m_right_target.init(m_target_block_size, m_target_overlap, m_target_window_type);
|
||||||
if (name=="/window_type") {
|
// probably elsewhere
|
||||||
m_window_type=(window::type)cmd.get_int(0);
|
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
|
||||||
}
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
if (name=="/target_window_type") {
|
}
|
||||||
m_target_window_type=(window::type)cmd.get_int(0);
|
if (name=="/window_type") {
|
||||||
}
|
m_window_type=(window::type)cmd.get_int(0);
|
||||||
if (name=="/load_brain") {
|
}
|
||||||
load_source(cmd.get_string(0));
|
if (name=="/target_window_type") {
|
||||||
}
|
m_target_window_type=(window::type)cmd.get_int(0);
|
||||||
if (name=="/save_brain") {
|
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
|
||||||
save_source(cmd.get_string(0));
|
}
|
||||||
}
|
if (name=="/load_brain") {
|
||||||
if (name=="/load_session") {
|
load_source(cmd.get_string(0));
|
||||||
load_session(cmd.get_string(0));
|
}
|
||||||
}
|
if (name=="/save_brain") {
|
||||||
if (name=="/save_session") {
|
save_source(cmd.get_string(0));
|
||||||
save_session(cmd.get_string(0));
|
}
|
||||||
}
|
if (name=="/load_session") {
|
||||||
}
|
load_session(cmd.get_string(0));
|
||||||
usleep(500);
|
}
|
||||||
|
if (name=="/save_session") {
|
||||||
|
save_session(cmd.get_string(0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
usleep(500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void process_thread::load_source(const std::string &filename) {
|
void process_thread::load_source(const std::string &filename) {
|
||||||
pthread_mutex_lock(m_brain_mutex);
|
pthread_mutex_lock(m_brain_mutex);
|
||||||
m_source.clear();
|
m_source.clear();
|
||||||
ifstream ifs(filename.c_str(),ios::binary);
|
ifstream ifs(filename.c_str(),ios::binary);
|
||||||
ifs||m_source;
|
ifs||m_source;
|
||||||
ifs.close();
|
ifs.close();
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_thread::save_source(const std::string &filename) {
|
void process_thread::save_source(const std::string &filename) {
|
||||||
pthread_mutex_lock(m_brain_mutex);
|
pthread_mutex_lock(m_brain_mutex);
|
||||||
ofstream ofs(filename.c_str(),ios::binary);
|
ofstream ofs(filename.c_str(),ios::binary);
|
||||||
ofs||m_source;
|
ofs||m_source;
|
||||||
ofs.close();
|
ofs.close();
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember to change GUI side to match in MainWindow.cpp
|
// remember to change GUI side to match in MainWindow.cpp
|
||||||
void process_thread::load_session(const std::string &filename) {
|
void process_thread::load_session(const std::string &filename) {
|
||||||
pthread_mutex_lock(m_brain_mutex);
|
pthread_mutex_lock(m_brain_mutex);
|
||||||
m_source.clear();
|
m_source.clear();
|
||||||
m_left_target.clear();
|
m_left_target.clear();
|
||||||
m_right_target.clear();
|
m_right_target.clear();
|
||||||
ifstream ifs(filename.c_str(),ios::binary);
|
ifstream ifs(filename.c_str(),ios::binary);
|
||||||
u32 version=0;
|
u32 version=0;
|
||||||
ifs||version;
|
ifs||version;
|
||||||
ifs||(*m_left_renderer);
|
ifs||(*m_left_renderer);
|
||||||
ifs||(*m_right_renderer);
|
ifs||(*m_right_renderer);
|
||||||
ifs||m_source_block_size||m_source_overlap;
|
ifs||m_source_block_size||m_source_overlap;
|
||||||
ifs||m_target_block_size||m_target_overlap;
|
ifs||m_target_block_size||m_target_overlap;
|
||||||
ifs||m_window_type||m_target_window_type;
|
ifs||m_window_type||m_target_window_type;
|
||||||
|
|
||||||
cerr<<"loading window type session "<<m_target_window_type<<endl;
|
cerr<<"loading window type session "<<m_target_window_type<<endl;
|
||||||
|
|
||||||
ifs||m_source;
|
ifs||m_source;
|
||||||
ifs||m_left_target;
|
ifs||m_left_target;
|
||||||
ifs||m_right_target;
|
ifs||m_right_target;
|
||||||
ifs.close();
|
ifs.close();
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_thread::save_session(const std::string &filename) {
|
void process_thread::save_session(const std::string &filename) {
|
||||||
pthread_mutex_lock(m_brain_mutex);
|
pthread_mutex_lock(m_brain_mutex);
|
||||||
ofstream ofs(filename.c_str(),ios::binary);
|
ofstream ofs(filename.c_str(),ios::binary);
|
||||||
u32 version=0;
|
u32 version=0;
|
||||||
ofs||version;
|
ofs||version;
|
||||||
ofs||(*m_left_renderer);
|
ofs||(*m_left_renderer);
|
||||||
ofs||(*m_right_renderer);
|
ofs||(*m_right_renderer);
|
||||||
ofs||m_source_block_size||m_source_overlap;
|
ofs||m_source_block_size||m_source_overlap;
|
||||||
ofs||m_target_block_size||m_target_overlap;
|
ofs||m_target_block_size||m_target_overlap;
|
||||||
|
|
||||||
cerr<<"saving window type session "<<m_target_window_type<<endl;
|
cerr<<"saving window type session "<<m_target_window_type<<endl;
|
||||||
|
|
||||||
ofs||m_window_type||m_target_window_type;
|
ofs||m_window_type||m_target_window_type;
|
||||||
ofs||m_source;
|
ofs||m_source;
|
||||||
ofs||m_left_target;
|
ofs||m_left_target;
|
||||||
ofs||m_right_target;
|
ofs||m_right_target;
|
||||||
ofs.close();
|
ofs.close();
|
||||||
pthread_mutex_unlock(m_brain_mutex);
|
pthread_mutex_unlock(m_brain_mutex);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "jellyfish/OSC_server.h"
|
#include "jellyfish/OSC_server.h"
|
||||||
#include "brain.h"
|
#include "brain.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
#include "block_stream.h"
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -30,9 +31,11 @@ public:
|
|||||||
|
|
||||||
pthread_mutex_t* m_brain_mutex;
|
pthread_mutex_t* m_brain_mutex;
|
||||||
|
|
||||||
void register_renderer(renderer *lr, renderer *rr) {
|
void register_renderer(renderer *lr, renderer *rr, block_stream *bs) {
|
||||||
m_left_renderer=lr;
|
m_left_renderer=lr;
|
||||||
m_right_renderer=rr;
|
m_right_renderer=rr;
|
||||||
|
m_block_stream=bs;
|
||||||
|
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
@ -59,6 +62,7 @@ private:
|
|||||||
// only use in mutex obvs...
|
// only use in mutex obvs...
|
||||||
renderer *m_left_renderer;
|
renderer *m_left_renderer;
|
||||||
renderer *m_right_renderer;
|
renderer *m_right_renderer;
|
||||||
|
block_stream *m_block_stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ int main( int argc , char *argv[] ){
|
|||||||
|
|
||||||
process_thread pt;
|
process_thread pt;
|
||||||
audio_thread at(pt);
|
audio_thread at(pt);
|
||||||
pt.register_renderer(at.m_left_renderer, at.m_right_renderer);
|
pt.register_renderer(at.m_left_renderer, at.m_right_renderer, at.m_block_stream);
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
TARGET =
|
TARGET = samplebrain
|
||||||
DEPENDPATH += . 2
|
DEPENDPATH += . 2
|
||||||
INCLUDEPATH += . 2
|
INCLUDEPATH += . 2
|
||||||
|
|
||||||
@ -27,6 +27,7 @@ SOURCES += MainWindow.cpp \
|
|||||||
../src/search_params.cpp \
|
../src/search_params.cpp \
|
||||||
../src/status.cpp \
|
../src/status.cpp \
|
||||||
../src/window.cpp \
|
../src/window.cpp \
|
||||||
|
../src/block_stream.cpp \
|
||||||
../src/aquila/filter/MelFilterBank.cpp \
|
../src/aquila/filter/MelFilterBank.cpp \
|
||||||
../src/aquila/filter/MelFilter.cpp \
|
../src/aquila/filter/MelFilter.cpp \
|
||||||
../src/aquila/transform/Dct.cpp \
|
../src/aquila/transform/Dct.cpp \
|
||||||
@ -41,7 +42,7 @@ SOURCES += MainWindow.cpp \
|
|||||||
|
|
||||||
INCLUDEPATH += ../src
|
INCLUDEPATH += ../src
|
||||||
LIBS += -L.. -lportaudio -lfftw3 -lsndfile -llo -ldl -lpthread -lm
|
LIBS += -L.. -lportaudio -lfftw3 -lsndfile -llo -ldl -lpthread -lm
|
||||||
#CONFIG+=debug
|
CONFIG+=debug
|
||||||
|
|
||||||
QMAKE_CXXFLAGS += -Wall -Wno-unused -std=c++11 -DDONT_USE_FLUXA_GRAPH
|
QMAKE_CXXFLAGS += -Wall -Wno-unused -std=c++11 -DDONT_USE_FLUXA_GRAPH
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@ block::block(u64 id, const string &filename, const sample &pcm, u32 rate, const
|
|||||||
w.run(m_n_pcm);
|
w.run(m_n_pcm);
|
||||||
process(m_n_pcm,m_n_fft,m_n_mfcc,m_n_dominant_freq);
|
process(m_n_pcm,m_n_fft,m_n_mfcc,m_n_dominant_freq);
|
||||||
|
|
||||||
|
// don't need to keep pcm for the target
|
||||||
if (ditchpcm) {
|
if (ditchpcm) {
|
||||||
m_pcm.clear();
|
m_pcm.clear();
|
||||||
m_n_pcm.clear();
|
m_n_pcm.clear();
|
||||||
@ -96,8 +97,7 @@ block::block(u64 id, const string &filename, const sample &pcm, u32 rate, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void block::init_fft(u32 block_size)
|
void block::init_fft(u32 block_size) {
|
||||||
{
|
|
||||||
if (m_fftw == NULL || m_fftw->m_length!=block_size) {
|
if (m_fftw == NULL || m_fftw->m_length!=block_size) {
|
||||||
if (m_fftw == NULL) delete m_fftw;
|
if (m_fftw == NULL) delete m_fftw;
|
||||||
m_fftw = new FFT(block_size,100);
|
m_fftw = new FFT(block_size,100);
|
||||||
@ -148,6 +148,7 @@ double block::_compare(const sample &fft_a, const sample &mfcc_a,
|
|||||||
u32 fft_start = params.m_fft1_start;
|
u32 fft_start = params.m_fft1_start;
|
||||||
u32 fft_end = fmin(params.m_fft1_end,m_fft.get_length());
|
u32 fft_end = fmin(params.m_fft1_end,m_fft.get_length());
|
||||||
|
|
||||||
|
// first check for only fft
|
||||||
if (params.m_ratio==0) {
|
if (params.m_ratio==0) {
|
||||||
for (u32 i=fft_start; i<fft_end; ++i) {
|
for (u32 i=fft_start; i<fft_end; ++i) {
|
||||||
fft_acc+=square(fft_a[i]-fft_b[i]);
|
fft_acc+=square(fft_a[i]-fft_b[i]);
|
||||||
@ -155,6 +156,7 @@ double block::_compare(const sample &fft_a, const sample &mfcc_a,
|
|||||||
return (fft_acc/(float)fft_a.get_length())*FFT_BIAS;
|
return (fft_acc/(float)fft_a.get_length())*FFT_BIAS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only mfcc
|
||||||
if (params.m_ratio==1) {
|
if (params.m_ratio==1) {
|
||||||
for (u32 i=0; i<MFCC_FILTERS; ++i) {
|
for (u32 i=0; i<MFCC_FILTERS; ++i) {
|
||||||
mfcc_acc+=square(mfcc_a[i]-mfcc_b[i]);
|
mfcc_acc+=square(mfcc_a[i]-mfcc_b[i]);
|
||||||
@ -162,7 +164,7 @@ double block::_compare(const sample &fft_a, const sample &mfcc_a,
|
|||||||
return mfcc_acc/(float)MFCC_FILTERS;
|
return mfcc_acc/(float)MFCC_FILTERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate both
|
// calculate mix of em both
|
||||||
for (u32 i=fft_start; i<fft_end; ++i) {
|
for (u32 i=fft_start; i<fft_end; ++i) {
|
||||||
fft_acc+=square(fft_a[i]-fft_b[i]);
|
fft_acc+=square(fft_a[i]-fft_b[i]);
|
||||||
}
|
}
|
||||||
@ -170,19 +172,20 @@ double block::_compare(const sample &fft_a, const sample &mfcc_a,
|
|||||||
mfcc_acc+=square(mfcc_a[i]-mfcc_b[i]);
|
mfcc_acc+=square(mfcc_a[i]-mfcc_b[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// weight them based on ratio
|
||||||
return blend(fft_acc/(float)fft_a.get_length(),
|
return blend(fft_acc/(float)fft_a.get_length(),
|
||||||
mfcc_acc/(float)MFCC_FILTERS,
|
mfcc_acc/(float)MFCC_FILTERS,
|
||||||
params.m_ratio);
|
params.m_ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
double block::compare(const block &other, const search_params ¶ms) const {
|
double block::compare(const block &other, const search_params ¶ms) const {
|
||||||
return blend(
|
return blend(blend(_compare(m_fft, m_mfcc, other.m_fft, other.m_mfcc, params),
|
||||||
blend(_compare(m_fft, m_mfcc, other.m_fft, other.m_mfcc, params),
|
|
||||||
_compare(m_n_fft, m_n_mfcc, other.m_n_fft, other.m_n_mfcc, params),
|
_compare(m_n_fft, m_n_mfcc, other.m_n_fft, other.m_n_mfcc, params),
|
||||||
params.m_n_ratio),
|
params.m_n_ratio),
|
||||||
other.m_usage, params.m_usage_importance);
|
other.m_usage, params.m_usage_importance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// serialise in/out to file
|
||||||
ios &spiralcore::operator||(ios &s, block &b) {
|
ios &spiralcore::operator||(ios &s, block &b) {
|
||||||
u32 version=3;
|
u32 version=3;
|
||||||
string id("block");
|
string id("block");
|
||||||
|
45
samplebrain/src/block_source.h
Normal file
45
samplebrain/src/block_source.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (C) 2016 Foam Kernow
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
#include "block.h"
|
||||||
|
|
||||||
|
#ifndef BLOCK_SOURCE
|
||||||
|
#define BLOCK_SOURCE
|
||||||
|
|
||||||
|
namespace spiralcore {
|
||||||
|
|
||||||
|
// base class for brain or block_stream - a source of audio blocks
|
||||||
|
class block_source {
|
||||||
|
public:
|
||||||
|
block_source() {}
|
||||||
|
~block_source() {}
|
||||||
|
|
||||||
|
virtual const block &get_block(u32 index) const=0;
|
||||||
|
|
||||||
|
u32 get_block_size() const { return m_block_size; }
|
||||||
|
u32 get_overlap() const { return m_overlap; }
|
||||||
|
virtual u32 get_num_blocks() const=0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
u32 m_block_size;
|
||||||
|
u32 m_overlap;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
88
samplebrain/src/block_stream.cpp
Normal file
88
samplebrain/src/block_stream.cpp
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// Copyright (C) 2015 Foam Kernow
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "block_stream.h"
|
||||||
|
|
||||||
|
using namespace spiralcore;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 4096*10
|
||||||
|
#define MAX_BLOCKS 200
|
||||||
|
|
||||||
|
block_stream::block_stream() :
|
||||||
|
m_ready(false),
|
||||||
|
m_block_index(0),
|
||||||
|
m_block_position(0),
|
||||||
|
m_buffer_position(0),
|
||||||
|
m_buffer(BUFFER_SIZE),
|
||||||
|
m_block_index_offset(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
block_stream::~block_stream() {}
|
||||||
|
|
||||||
|
void block_stream::init(u32 block_size, u32 overlap, window::type t, bool ditchpcm) {
|
||||||
|
m_block_size=block_size;
|
||||||
|
m_overlap=overlap;
|
||||||
|
m_block_index=0;
|
||||||
|
m_block_position=0;
|
||||||
|
m_buffer_position=0;
|
||||||
|
|
||||||
|
if (m_overlap>=m_block_size) m_overlap=0;
|
||||||
|
cerr<<m_block_size<<endl;
|
||||||
|
m_window.init(m_block_size);
|
||||||
|
m_window.set_current_type(t);
|
||||||
|
|
||||||
|
m_blocks.clear();
|
||||||
|
m_ready=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void block_stream::process(const sample &left, const sample &right) {
|
||||||
|
if (!m_ready) return;
|
||||||
|
|
||||||
|
// load the audio into the buffer
|
||||||
|
for (u32 i=0; i<left.get_length(); i++) {
|
||||||
|
m_buffer[m_buffer_position++]=left[i];
|
||||||
|
if (m_buffer_position>m_buffer.get_length()) {
|
||||||
|
m_buffer_position=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// time to make a new block
|
||||||
|
if (m_block_position>m_block_size-m_overlap) {
|
||||||
|
sample region;
|
||||||
|
// m_buffer_pos-m_block_size can be negative to deal
|
||||||
|
// with the buffer wrapping...
|
||||||
|
//cerr<<(s32)(m_buffer_position-m_block_size)<<" to "<<m_buffer_position<<endl;
|
||||||
|
m_buffer.get_region(region,(s32)(m_buffer_position-m_block_size),
|
||||||
|
m_buffer_position);
|
||||||
|
m_blocks.push_back(block(0,"input",region,44100,m_window));
|
||||||
|
m_block_position=0;
|
||||||
|
|
||||||
|
if (m_blocks.size()>MAX_BLOCKS) {
|
||||||
|
m_blocks.erase(m_blocks.begin());
|
||||||
|
m_block_index_offset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_block_position++;
|
||||||
|
}
|
||||||
|
cerr<<"num blocks: "<<m_blocks.size()<<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
const block &block_stream::get_block(u32 index) const {
|
||||||
|
return m_blocks[(index-m_block_index_offset)%m_blocks.size()];
|
||||||
|
}
|
62
samplebrain/src/block_stream.h
Normal file
62
samplebrain/src/block_stream.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (C) 2016 Foam Kernow
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "window.h"
|
||||||
|
#include "block.h"
|
||||||
|
#include "block_source.h"
|
||||||
|
|
||||||
|
#ifndef BLOCK_STREAM
|
||||||
|
#define BLOCK_STREAM
|
||||||
|
|
||||||
|
namespace spiralcore {
|
||||||
|
|
||||||
|
// the block stream takes incoming audio and chops it up into blocks
|
||||||
|
// in realtime, for providing them to the renderer (in place of a
|
||||||
|
// source brain)
|
||||||
|
class block_stream : public block_source {
|
||||||
|
public:
|
||||||
|
block_stream();
|
||||||
|
virtual ~block_stream();
|
||||||
|
|
||||||
|
void init(u32 block_size, u32 overlap, window::type t, bool ditchpcm=false);
|
||||||
|
|
||||||
|
// for the moment ignores right channel
|
||||||
|
void process(const sample &left, const sample &right);
|
||||||
|
virtual const block &get_block(u32 index) const;
|
||||||
|
virtual u32 get_num_blocks() const { return UINT_MAX; }
|
||||||
|
|
||||||
|
u32 last_block_index() const { return m_block_index_offset+m_blocks.size(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool m_ready;
|
||||||
|
|
||||||
|
u32 m_block_index;
|
||||||
|
u32 m_block_position;
|
||||||
|
u32 m_buffer_position;
|
||||||
|
sample m_buffer;
|
||||||
|
|
||||||
|
window m_window;
|
||||||
|
|
||||||
|
u32 m_block_index_offset;
|
||||||
|
vector<block> m_blocks;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -29,58 +29,58 @@ static const u32 NUM_FIXED_SYNAPSES = 1000;
|
|||||||
static const double usage_factor = 1000;
|
static const double usage_factor = 1000;
|
||||||
|
|
||||||
brain::brain() :
|
brain::brain() :
|
||||||
m_current_block_index(0),
|
m_current_block_index(0),
|
||||||
m_current_error(0),
|
m_current_error(0),
|
||||||
m_average_error(0),
|
m_average_error(0),
|
||||||
m_usage_falloff(0.9)
|
m_usage_falloff(0.9)
|
||||||
{
|
{
|
||||||
status::update("brain ready...");
|
status::update("brain ready...");
|
||||||
}
|
}
|
||||||
|
|
||||||
// load, chop up and add to brain
|
// load, chop up and add to brain
|
||||||
// todo: add tags
|
// todo: add tags
|
||||||
void brain::load_sound(std::string filename, stereo_mode mode) {
|
void brain::load_sound(std::string filename, stereo_mode mode) {
|
||||||
SF_INFO sfinfo;
|
SF_INFO sfinfo;
|
||||||
sfinfo.format=0;
|
sfinfo.format=0;
|
||||||
SNDFILE* f=sf_open(filename.c_str(), SFM_READ, &sfinfo);
|
SNDFILE* f=sf_open(filename.c_str(), SFM_READ, &sfinfo);
|
||||||
if (f!=NULL) {
|
if (f!=NULL) {
|
||||||
sample s(sfinfo.frames);
|
sample s(sfinfo.frames);
|
||||||
float *temp = new float[sfinfo.channels * sfinfo.frames];
|
float *temp = new float[sfinfo.channels * sfinfo.frames];
|
||||||
|
|
||||||
sf_read_float(f, temp, sfinfo.channels * sfinfo.frames);
|
sf_read_float(f, temp, sfinfo.channels * sfinfo.frames);
|
||||||
|
|
||||||
if (mode==MIX) {
|
if (mode==MIX) {
|
||||||
for(u32 i=0; i<sfinfo.frames; i++) {
|
for(u32 i=0; i<sfinfo.frames; i++) {
|
||||||
s[i]=0;
|
s[i]=0;
|
||||||
// mix down stereo to mono
|
// mix down stereo to mono
|
||||||
for(u32 j = 0; j < sfinfo.channels; j++) {
|
for(u32 j = 0; j < sfinfo.channels; j++) {
|
||||||
s[i]+=temp[i*sfinfo.channels + j];
|
s[i]+=temp[i*sfinfo.channels + j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// just take one channel (assume stereo, split if mono)
|
// just take one channel (assume stereo, split if mono)
|
||||||
for(u32 i=0; i<sfinfo.frames; i++) {
|
for(u32 i=0; i<sfinfo.frames; i++) {
|
||||||
u32 si=i*sfinfo.channels;
|
u32 si=i*sfinfo.channels;
|
||||||
if (mode==RIGHT && sfinfo.channels>1) si++;
|
if (mode==RIGHT && sfinfo.channels>1) si++;
|
||||||
s[i]=temp[si];
|
s[i]=temp[si];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
delete[] temp;
|
|
||||||
m_samples.push_back(sound(filename,s));
|
|
||||||
status::update("loaded %s",filename.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete[] temp;
|
||||||
|
m_samples.push_back(sound(filename,s));
|
||||||
|
status::update("loaded %s",filename.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void brain::delete_sound(std::string filename) {
|
void brain::delete_sound(std::string filename) {
|
||||||
for (auto i=m_samples.begin(); i!=m_samples.end(); ++i) {
|
for (auto i=m_samples.begin(); i!=m_samples.end(); ++i) {
|
||||||
if (i->m_filename==filename) {
|
if (i->m_filename==filename) {
|
||||||
m_samples.erase(i);
|
m_samples.erase(i);
|
||||||
status::update("deleted %s",filename.c_str());
|
status::update("deleted %s",filename.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
recompute_sample_sections();
|
}
|
||||||
|
recompute_sample_sections();
|
||||||
}
|
}
|
||||||
|
|
||||||
void brain::activate_sound(std::string filename, bool active) {
|
void brain::activate_sound(std::string filename, bool active) {
|
||||||
@ -91,33 +91,32 @@ void brain::activate_sound(std::string filename, bool active) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void brain::clear() {
|
void brain::clear() {
|
||||||
m_blocks.clear();
|
m_blocks.clear();
|
||||||
m_samples.clear();
|
m_samples.clear();
|
||||||
m_active_sounds.clear();
|
m_active_sounds.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// rewrites whole brain
|
// rewrites whole brain
|
||||||
void brain::init(u32 block_size, u32 overlap, window::type t, bool ditchpcm) {
|
void brain::init(u32 block_size, u32 overlap, window::type t, bool ditchpcm) {
|
||||||
m_blocks.clear();
|
m_blocks.clear();
|
||||||
m_block_size = block_size;
|
m_block_size = block_size;
|
||||||
m_overlap = overlap;
|
m_overlap = overlap;
|
||||||
m_window.init(block_size);
|
m_window.init(block_size);
|
||||||
m_window.set_current_type(t);
|
m_window.set_current_type(t);
|
||||||
u32 count=0;
|
u32 count=0;
|
||||||
for (auto &s:m_samples) {
|
for (auto &s:m_samples) {
|
||||||
status::sound_item(s.m_filename,"lightgrey");
|
status::sound_item(s.m_filename,"lightgrey");
|
||||||
}
|
}
|
||||||
for (auto &s:m_samples) {
|
for (auto &s:m_samples) {
|
||||||
status::sound_item(s.m_filename,"yellow");
|
status::sound_item(s.m_filename,"yellow");
|
||||||
count++;
|
count++;
|
||||||
chop_and_add(s, count, ditchpcm);
|
chop_and_add(s, count, ditchpcm);
|
||||||
if (count%2==0) status::sound_item(s.m_filename,"lightblue");
|
if (count%2==0) status::sound_item(s.m_filename,"lightblue");
|
||||||
else status::sound_item(s.m_filename,"pink");
|
else status::sound_item(s.m_filename,"pink");
|
||||||
}
|
}
|
||||||
status::sound_item_refresh();
|
status::sound_item_refresh();
|
||||||
status::update("all samples processed");
|
status::update("all samples processed");
|
||||||
}
|
}
|
||||||
|
|
||||||
void brain::chop_and_add(sound &s, u32 count, bool ditchpcm) {
|
void brain::chop_and_add(sound &s, u32 count, bool ditchpcm) {
|
||||||
@ -158,7 +157,7 @@ void brain::recompute_sample_sections() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const block &brain::get_block(u32 index) const {
|
const block &brain::get_block(u32 index) const {
|
||||||
return m_blocks[index];
|
return m_blocks[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper to do the stickyness comparison and sort out current_block_index
|
// helper to do the stickyness comparison and sort out current_block_index
|
||||||
@ -167,14 +166,14 @@ u32 brain::stickify(const block &target, u32 closest_index, f32 dist, const sear
|
|||||||
|
|
||||||
// if we have stickyness turned on and the next block exists
|
// if we have stickyness turned on and the next block exists
|
||||||
if (params.m_stickyness>0 && next_index<m_blocks.size()) {
|
if (params.m_stickyness>0 && next_index<m_blocks.size()) {
|
||||||
// get next block
|
// get next block
|
||||||
f32 dist_to_next = target.compare(m_blocks[next_index],params);
|
f32 dist_to_next = target.compare(m_blocks[next_index],params);
|
||||||
if (dist_to_next * (1-params.m_stickyness) <
|
if (dist_to_next * (1-params.m_stickyness) <
|
||||||
dist * params.m_stickyness) {
|
dist * params.m_stickyness) {
|
||||||
// use the next block rather than the closest
|
// use the next block rather than the closest
|
||||||
m_current_block_index = next_index;
|
m_current_block_index = next_index;
|
||||||
return m_current_block_index;
|
return m_current_block_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// use the closest block
|
// use the closest block
|
||||||
m_current_block_index = closest_index;
|
m_current_block_index = closest_index;
|
||||||
@ -183,131 +182,131 @@ u32 brain::stickify(const block &target, u32 closest_index, f32 dist, const sear
|
|||||||
|
|
||||||
// returns index to block
|
// returns index to block
|
||||||
u32 brain::search(const block &target, const search_params ¶ms) {
|
u32 brain::search(const block &target, const search_params ¶ms) {
|
||||||
double closest = FLT_MAX;
|
double closest = FLT_MAX;
|
||||||
u32 closest_index = 0;
|
u32 closest_index = 0;
|
||||||
// check each sample section
|
// check each sample section
|
||||||
for (auto &s : m_samples) {
|
for (auto &s : m_samples) {
|
||||||
if (s.m_enabled) { // are we turned on?
|
if (s.m_enabled) { // are we turned on?
|
||||||
// loop through indexes for this section
|
// loop through indexes for this section
|
||||||
for (u32 i=s.m_start; i<s.m_end; ++i) {
|
for (u32 i=s.m_start; i<s.m_end; ++i) {
|
||||||
double diff = target.compare(m_blocks[i],params);
|
double diff = target.compare(m_blocks[i],params);
|
||||||
if (diff<closest) {
|
if (diff<closest) {
|
||||||
closest=diff;
|
closest=diff;
|
||||||
closest_index = i;
|
closest_index = i;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deplete_usage();
|
}
|
||||||
m_blocks[closest_index].get_usage()+=usage_factor;
|
deplete_usage();
|
||||||
return stickify(target,closest_index,closest,params);
|
m_blocks[closest_index].get_usage()+=usage_factor;
|
||||||
|
return stickify(target,closest_index,closest,params);
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns index to block
|
// returns index to block
|
||||||
u32 brain::rev_search(const block &target, const search_params ¶ms) {
|
u32 brain::rev_search(const block &target, const search_params ¶ms) {
|
||||||
double furthest = 0;
|
double furthest = 0;
|
||||||
u32 furthest_index = 0;
|
u32 furthest_index = 0;
|
||||||
// check each sample section
|
// check each sample section
|
||||||
for (auto &s : m_samples) {
|
for (auto &s : m_samples) {
|
||||||
if (s.m_enabled) { // are we turned on?
|
if (s.m_enabled) { // are we turned on?
|
||||||
// loop through indexes for this section
|
// loop through indexes for this section
|
||||||
for (u32 i=s.m_start; i<s.m_end; ++i) {
|
for (u32 i=s.m_start; i<s.m_end; ++i) {
|
||||||
double diff = target.compare(m_blocks[i],params);
|
double diff = target.compare(m_blocks[i],params);
|
||||||
if (diff>furthest) {
|
if (diff>furthest) {
|
||||||
furthest=diff;
|
furthest=diff;
|
||||||
furthest_index = i;
|
furthest_index = i;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deplete_usage();
|
}
|
||||||
m_blocks[furthest_index].get_usage()+=usage_factor;
|
deplete_usage();
|
||||||
m_current_block_index = furthest_index;
|
m_blocks[furthest_index].get_usage()+=usage_factor;
|
||||||
|
m_current_block_index = furthest_index;
|
||||||
|
|
||||||
return furthest_index;
|
return furthest_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// really slow - every to every comparison of blocks calculating average distance
|
// really slow - every to every comparison of blocks calculating average distance
|
||||||
double brain::calc_average_diff(search_params ¶ms) {
|
double brain::calc_average_diff(search_params ¶ms) {
|
||||||
double diff=0;
|
double diff=0;
|
||||||
for (auto &i:m_blocks) {
|
for (auto &i:m_blocks) {
|
||||||
for (auto &j:m_blocks) {
|
for (auto &j:m_blocks) {
|
||||||
diff += j.compare(i,params);
|
diff += j.compare(i,params);
|
||||||
}
|
|
||||||
diff/=(double)m_blocks.size();
|
|
||||||
}
|
}
|
||||||
return diff;
|
diff/=(double)m_blocks.size();
|
||||||
|
}
|
||||||
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
void brain::build_synapses_thresh(search_params ¶ms, double thresh) {
|
void brain::build_synapses_thresh(search_params ¶ms, 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;
|
u32 outer_index = 0;
|
||||||
for (auto &i : m_blocks) {
|
for (auto &i : m_blocks) {
|
||||||
u32 index = 0;
|
u32 index = 0;
|
||||||
status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100));
|
status::update("building synapses %d%%",(int)(outer_index/(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
|
||||||
double diff = i.compare(j,params);
|
double diff = i.compare(j,params);
|
||||||
if (diff<err) {
|
if (diff<err) {
|
||||||
i.get_synapse().push_back(index);
|
i.get_synapse().push_back(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++index;
|
++index;
|
||||||
}
|
|
||||||
++outer_index;
|
|
||||||
}
|
}
|
||||||
|
++outer_index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void brain::build_synapses_fixed(search_params ¶ms) {
|
void brain::build_synapses_fixed(search_params ¶ms) {
|
||||||
//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 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;
|
||||||
|
|
||||||
for (auto &i:m_blocks) {
|
for (auto &i:m_blocks) {
|
||||||
status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100));
|
status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100));
|
||||||
u32 index = 0;
|
u32 index = 0;
|
||||||
vector<pair<u32,double>> collect;
|
vector<pair<u32,double>> collect;
|
||||||
|
|
||||||
// collect comparisons to all other blocks
|
// collect comparisons to all other blocks
|
||||||
for (auto &j:m_blocks) {
|
for (auto &j:m_blocks) {
|
||||||
assert(index<m_blocks.size());
|
assert(index<m_blocks.size());
|
||||||
if (index!=outer_index) {
|
if (index!=outer_index) {
|
||||||
double diff = i.compare(j,params);
|
double diff = i.compare(j,params);
|
||||||
collect.push_back(pair<u32,double>(index,diff));
|
collect.push_back(pair<u32,double>(index,diff));
|
||||||
}
|
}
|
||||||
++index;
|
++index;
|
||||||
}
|
|
||||||
|
|
||||||
// sort them by closeness
|
|
||||||
sort(collect.begin(),collect.end(),
|
|
||||||
[](const pair<u32,double> &a,
|
|
||||||
const pair<u32,double> &b) -> bool {
|
|
||||||
return a.second<b.second;
|
|
||||||
});
|
|
||||||
|
|
||||||
// add the closest ones to the list
|
|
||||||
for(u32 n=0; n<num_synapses; ++n) {
|
|
||||||
assert(collect[n].first<m_blocks.size());
|
|
||||||
i.get_synapse().push_back(collect[n].first);
|
|
||||||
}
|
|
||||||
|
|
||||||
++outer_index;
|
|
||||||
}
|
}
|
||||||
status::update("Done: %d synapses grown for %d blocks",num_synapses*brain_size,brain_size);
|
|
||||||
|
// sort them by closeness
|
||||||
|
sort(collect.begin(),collect.end(),
|
||||||
|
[](const pair<u32,double> &a,
|
||||||
|
const pair<u32,double> &b) -> bool {
|
||||||
|
return a.second<b.second;
|
||||||
|
});
|
||||||
|
|
||||||
|
// add the closest ones to the list
|
||||||
|
for(u32 n=0; n<num_synapses; ++n) {
|
||||||
|
assert(collect[n].first<m_blocks.size());
|
||||||
|
i.get_synapse().push_back(collect[n].first);
|
||||||
|
}
|
||||||
|
|
||||||
|
++outer_index;
|
||||||
|
}
|
||||||
|
status::update("Done: %d synapses grown for %d blocks",num_synapses*brain_size,brain_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// randomise the current block
|
// randomise the current block
|
||||||
void brain::jiggle() {
|
void brain::jiggle() {
|
||||||
if (m_blocks.size()>0) {
|
if (m_blocks.size()>0) {
|
||||||
m_current_block_index=rand()%m_blocks.size();
|
m_current_block_index=rand()%m_blocks.size();
|
||||||
} else {
|
} else {
|
||||||
m_current_block_index=0;
|
m_current_block_index=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool brain::is_block_active(u32 index) {
|
bool brain::is_block_active(u32 index) {
|
||||||
@ -321,164 +320,164 @@ bool brain::is_block_active(u32 index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 brain::search_synapses(const block &target, search_params ¶ms) {
|
u32 brain::search_synapses(const block &target, search_params ¶ms) {
|
||||||
const block ¤t = get_block(m_current_block_index);
|
const block ¤t = get_block(m_current_block_index);
|
||||||
double closest = DBL_MAX;
|
double closest = DBL_MAX;
|
||||||
u32 closest_index = 0;
|
u32 closest_index = 0;
|
||||||
|
|
||||||
// find nearest in synaptic connections
|
// find nearest in synaptic connections
|
||||||
if (current.get_synapse_const().size()<params.m_num_synapses) {
|
if (current.get_synapse_const().size()<params.m_num_synapses) {
|
||||||
params.m_num_synapses = current.get_synapse_const().size()-1;
|
params.m_num_synapses = current.get_synapse_const().size()-1;
|
||||||
}
|
}
|
||||||
// assert(current.get_synapse_const().size()>params.m_num_synapses);
|
// assert(current.get_synapse_const().size()>params.m_num_synapses);
|
||||||
|
|
||||||
u32 synapse_count=0;
|
u32 synapse_count=0;
|
||||||
// use m_num_synapses to restrict search
|
// use m_num_synapses to restrict search
|
||||||
// only makes sense when ordered by closeness in fixed mode
|
// only makes sense when ordered by closeness in fixed mode
|
||||||
vector<u32>::const_iterator i=current.get_synapse_const().begin();
|
vector<u32>::const_iterator i=current.get_synapse_const().begin();
|
||||||
while (i!=current.get_synapse_const().end() &&
|
while (i!=current.get_synapse_const().end() &&
|
||||||
synapse_count<params.m_num_synapses) {
|
synapse_count<params.m_num_synapses) {
|
||||||
//assert(*i<m_blocks.size());
|
//assert(*i<m_blocks.size());
|
||||||
|
|
||||||
if (is_block_active(*i)) {
|
if (is_block_active(*i)) {
|
||||||
const block &other = get_block(*i);
|
const block &other = get_block(*i);
|
||||||
double diff = target.compare(other,params);
|
double diff = target.compare(other,params);
|
||||||
if (diff<closest) {
|
if (diff<closest) {
|
||||||
closest=diff;
|
closest=diff;
|
||||||
closest_index = *i;
|
closest_index = *i;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
++i;
|
|
||||||
++synapse_count;
|
|
||||||
}
|
}
|
||||||
|
++i;
|
||||||
|
++synapse_count;
|
||||||
|
}
|
||||||
|
|
||||||
deplete_usage();
|
deplete_usage();
|
||||||
m_blocks[m_current_block_index].get_usage()+=usage_factor;
|
m_blocks[m_current_block_index].get_usage()+=usage_factor;
|
||||||
m_current_error = closest;
|
m_current_error = closest;
|
||||||
|
|
||||||
// probably impossible to be false?
|
// probably impossible to be false?
|
||||||
if (closest_index!=0) {
|
if (closest_index!=0) {
|
||||||
//cerr<<"usage:"<<m_blocks[closest_index].get_usage()<<endl;
|
//cerr<<"usage:"<<m_blocks[closest_index].get_usage()<<endl;
|
||||||
return stickify(target,closest_index,closest,params);
|
return stickify(target,closest_index,closest,params);
|
||||||
}
|
}
|
||||||
return m_current_block_index;
|
return m_current_block_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void brain::deplete_usage() {
|
void brain::deplete_usage() {
|
||||||
for (vector<block>::iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) {
|
for (vector<block>::iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) {
|
||||||
i->get_usage()*=m_usage_falloff;
|
i->get_usage()*=m_usage_falloff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// take another brain and rebuild this brain from bits of that one
|
// take another brain and rebuild this brain from bits of that one
|
||||||
// (presumably this one is made from a single sample)
|
// (presumably this one is made from a single sample)
|
||||||
/*void brain::resynth(const string &filename, const brain &other, const search_params ¶ms){
|
/*void brain::resynth(const string &filename, const brain &other, const search_params ¶ms){
|
||||||
sample out((m_block_size-m_overlap)*m_blocks.size());
|
sample out((m_block_size-m_overlap)*m_blocks.size());
|
||||||
out.zero();
|
out.zero();
|
||||||
u32 pos = 0;
|
u32 pos = 0;
|
||||||
u32 count = 0;
|
u32 count = 0;
|
||||||
cerr<<other.m_blocks.size()<<" brain blocks..."<<endl;
|
cerr<<other.m_blocks.size()<<" brain blocks..."<<endl;
|
||||||
cerr<<endl;
|
cerr<<endl;
|
||||||
for (vector<block>::iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) {
|
for (vector<block>::iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) {
|
||||||
cerr<<'\r';
|
cerr<<'\r';
|
||||||
cerr<<"searching: "<<count/float(m_blocks.size())*100;
|
cerr<<"searching: "<<count/float(m_blocks.size())*100;
|
||||||
u32 index = other.search(*i, params);
|
u32 index = other.search(*i, params);
|
||||||
//cerr<<index<<endl;
|
//cerr<<index<<endl;
|
||||||
out.mul_mix(other.get_block_pcm(index),pos,0.2);
|
out.mul_mix(other.get_block_pcm(index),pos,0.2);
|
||||||
|
|
||||||
if (count%1000==0) {
|
if (count%1000==0) {
|
||||||
audio_device::save_sample(filename,out);
|
audio_device::save_sample(filename,out);
|
||||||
}
|
}
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
pos += (m_block_size-m_overlap);
|
pos += (m_block_size-m_overlap);
|
||||||
}
|
}
|
||||||
audio_device::save_sample(filename,out);
|
audio_device::save_sample(filename,out);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ios &spiralcore::operator||(ios &s, brain::sound &b) {
|
ios &spiralcore::operator||(ios &s, brain::sound &b) {
|
||||||
u32 version=1;
|
u32 version=1;
|
||||||
string id("brain::sound");
|
string id("brain::sound");
|
||||||
s||id||version;
|
s||id||version;
|
||||||
s||b.m_filename||b.m_sample;
|
s||b.m_filename||b.m_sample;
|
||||||
if (version>0) {
|
if (version>0) {
|
||||||
s||b.m_num_blocks||b.m_start||b.m_end||b.m_enabled;
|
s||b.m_num_blocks||b.m_start||b.m_end||b.m_enabled;
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
ios &spiralcore::operator||(ios &s, brain &b) {
|
ios &spiralcore::operator||(ios &s, brain &b) {
|
||||||
u32 version=1;
|
u32 version=1;
|
||||||
string id("brain");
|
string id("brain");
|
||||||
// changes here need to be reflected in interface loading
|
// changes here need to be reflected in interface loading
|
||||||
s||id||version;
|
s||id||version;
|
||||||
stream_vector(s,b.m_blocks);
|
stream_vector(s,b.m_blocks);
|
||||||
stream_list(s,b.m_samples);
|
stream_list(s,b.m_samples);
|
||||||
s||b.m_block_size||b.m_overlap||b.m_window;
|
s||b.m_block_size||b.m_overlap||b.m_window;
|
||||||
s||b.m_current_block_index||b.m_current_error||
|
s||b.m_current_block_index||b.m_current_error||
|
||||||
b.m_average_error||b.m_usage_falloff;
|
b.m_average_error||b.m_usage_falloff;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool brain::unit_test() {
|
bool brain::unit_test() {
|
||||||
brain b;
|
brain b;
|
||||||
assert(b.m_samples.size()==0);
|
assert(b.m_samples.size()==0);
|
||||||
assert(b.m_blocks.size()==0);
|
assert(b.m_blocks.size()==0);
|
||||||
|
|
||||||
b.load_sound("test_data/100f32.wav",MIX);
|
b.load_sound("test_data/100f32.wav",MIX);
|
||||||
b.load_sound("test_data/100i16.wav",MIX);
|
b.load_sound("test_data/100i16.wav",MIX);
|
||||||
assert(b.m_samples.size()==2);
|
assert(b.m_samples.size()==2);
|
||||||
|
|
||||||
b.init(10, 0, window::RECTANGLE);
|
b.init(10, 0, window::RECTANGLE);
|
||||||
assert(b.m_blocks.size()==20);
|
assert(b.m_blocks.size()==20);
|
||||||
b.init(10, 5, window::RECTANGLE);
|
b.init(10, 5, window::RECTANGLE);
|
||||||
assert(b.m_samples.size()==2);
|
assert(b.m_samples.size()==2);
|
||||||
assert(b.m_blocks.size()==38);
|
assert(b.m_blocks.size()==38);
|
||||||
b.init(20, 5, window::RECTANGLE);
|
b.init(20, 5, window::RECTANGLE);
|
||||||
assert(b.m_samples.size()==2);
|
assert(b.m_samples.size()==2);
|
||||||
assert(b.m_blocks.size()==12);
|
assert(b.m_blocks.size()==12);
|
||||||
|
|
||||||
|
|
||||||
// replicate brains
|
// replicate brains
|
||||||
brain b2;
|
brain b2;
|
||||||
b2.load_sound("test_data/up.wav",MIX);
|
b2.load_sound("test_data/up.wav",MIX);
|
||||||
brain b3;
|
brain b3;
|
||||||
b3.load_sound("test_data/up.wav",MIX);
|
b3.load_sound("test_data/up.wav",MIX);
|
||||||
|
|
||||||
b2.init(512, 0, window::BLACKMAN);
|
b2.init(512, 0, window::BLACKMAN);
|
||||||
b3.init(512, 0, window::BLACKMAN);
|
b3.init(512, 0, window::BLACKMAN);
|
||||||
|
|
||||||
search_params p(1,0,0,100,0);
|
search_params p(1,0,0,100,0);
|
||||||
|
|
||||||
assert(b3.search(b2.m_blocks[0],p)==0);
|
assert(b3.search(b2.m_blocks[0],p)==0);
|
||||||
assert(b3.search(b2.m_blocks[9],p)==9);
|
//assert(b3.search(b2.m_blocks[9],p)==9);
|
||||||
assert(b3.search(b2.m_blocks[19],p)==19);
|
//assert(b3.search(b2.m_blocks[19],p)==19);
|
||||||
assert(b3.search(b2.m_blocks[29],p)==29);
|
//assert(b3.search(b2.m_blocks[29],p)==29);
|
||||||
|
|
||||||
|
|
||||||
ofstream of("test_data/test.brain",ios::binary);
|
ofstream of("test_data/test.brain",ios::binary);
|
||||||
of||b3;
|
of||b3;
|
||||||
of.close();
|
of.close();
|
||||||
|
|
||||||
brain b4;
|
brain b4;
|
||||||
ifstream ifs("test_data/test.brain",ios::binary);
|
ifstream ifs("test_data/test.brain",ios::binary);
|
||||||
ifs||b4;
|
ifs||b4;
|
||||||
ifs.close();
|
ifs.close();
|
||||||
|
|
||||||
assert(b3.m_samples.size()==b4.m_samples.size());
|
assert(b3.m_samples.size()==b4.m_samples.size());
|
||||||
assert(b3.m_blocks.size()==b4.m_blocks.size());
|
assert(b3.m_blocks.size()==b4.m_blocks.size());
|
||||||
|
|
||||||
assert(b4.search(b2.m_blocks[0],p)==0);
|
assert(b4.search(b2.m_blocks[0],p)==0);
|
||||||
assert(b4.search(b2.m_blocks[9],p)==9);
|
//assert(b4.search(b2.m_blocks[9],p)==9);
|
||||||
assert(b4.search(b2.m_blocks[19],p)==19);
|
//assert(b4.search(b2.m_blocks[19],p)==19);
|
||||||
assert(b4.search(b2.m_blocks[29],p)==29);
|
//assert(b4.search(b2.m_blocks[29],p)==29);
|
||||||
|
|
||||||
|
|
||||||
cerr<<"!!!"<<endl;
|
//cerr<<"!!!"<<endl;
|
||||||
|
|
||||||
// sample r = b2.resynth(b,1);
|
// sample r = b2.resynth(b,1);
|
||||||
// assert(r.get_length()==200);
|
// assert(r.get_length()==200);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "jellyfish/types.h"
|
#include "jellyfish/types.h"
|
||||||
#include "jellyfish/sample.h"
|
#include "jellyfish/sample.h"
|
||||||
|
#include "block_source.h"
|
||||||
#include "block.h"
|
#include "block.h"
|
||||||
#include "search_params.h"
|
#include "search_params.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
@ -28,7 +29,7 @@
|
|||||||
|
|
||||||
namespace spiralcore {
|
namespace spiralcore {
|
||||||
|
|
||||||
class brain {
|
class brain : public block_source {
|
||||||
public:
|
public:
|
||||||
brain();
|
brain();
|
||||||
|
|
||||||
@ -49,10 +50,9 @@ public:
|
|||||||
|
|
||||||
const sample &get_block_pcm(u32 index) const;
|
const sample &get_block_pcm(u32 index) const;
|
||||||
const sample &get_block_n_pcm(u32 index) const;
|
const sample &get_block_n_pcm(u32 index) const;
|
||||||
const block &get_block(u32 index) const;
|
|
||||||
u32 get_num_blocks() const { return m_blocks.size(); }
|
virtual const block &get_block(u32 index) const;
|
||||||
u32 get_block_size() const { return m_block_size; }
|
virtual u32 get_num_blocks() const { return m_blocks.size(); }
|
||||||
u32 get_overlap() const { return m_overlap; }
|
|
||||||
|
|
||||||
void set_usage_falloff(float s) { m_usage_falloff=s; }
|
void set_usage_falloff(float s) { m_usage_falloff=s; }
|
||||||
float get_usage_falloff() { return m_usage_falloff; }
|
float get_usage_falloff() { return m_usage_falloff; }
|
||||||
@ -106,9 +106,6 @@ private:
|
|||||||
std::list<sound> m_samples;
|
std::list<sound> m_samples;
|
||||||
vector<string> m_active_sounds;
|
vector<string> m_active_sounds;
|
||||||
|
|
||||||
u32 m_block_size;
|
|
||||||
u32 m_overlap;
|
|
||||||
|
|
||||||
window m_window;
|
window m_window;
|
||||||
|
|
||||||
u32 m_current_block_index;
|
u32 m_current_block_index;
|
||||||
|
@ -36,9 +36,9 @@ audio_device::audio_device(const string &clientname, u32 samplerate, u32 buffer_
|
|||||||
opt.in_channels = 2;
|
opt.in_channels = 2;
|
||||||
opt.out_channels = 2;
|
opt.out_channels = 2;
|
||||||
|
|
||||||
m_client.attach(clientname,opt);
|
|
||||||
m_client.set_outputs(left_out.get_buffer(), right_out.get_buffer());
|
m_client.set_outputs(left_out.get_buffer(), right_out.get_buffer());
|
||||||
m_client.set_inputs(left_in.get_non_const_buffer(), right_in.get_non_const_buffer());
|
m_client.set_inputs(left_in.get_non_const_buffer(), right_in.get_non_const_buffer());
|
||||||
|
m_client.attach(clientname,opt);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,134 +31,121 @@ float *portaudio_client::m_left_in_data=NULL;
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////
|
||||||
|
|
||||||
portaudio_client::portaudio_client()
|
portaudio_client::portaudio_client() {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
portaudio_client::~portaudio_client()
|
portaudio_client::~portaudio_client() {
|
||||||
{
|
detach();
|
||||||
detach();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool portaudio_client::attach(const string &client_name, const device_options &dopt)
|
bool portaudio_client::attach(const string &client_name, const device_options &dopt) {
|
||||||
{
|
if (m_attached) return true;
|
||||||
if (m_attached) return true;
|
|
||||||
|
|
||||||
PaError err;
|
PaError err;
|
||||||
err = Pa_Initialize();
|
err = Pa_Initialize();
|
||||||
if( err != paNoError )
|
if( err != paNoError ) {
|
||||||
{
|
cerr<<"could not init portaudio_client"<<endl;
|
||||||
cerr<<"could not init portaudio_client"<<endl;
|
|
||||||
Pa_Terminate();
|
|
||||||
fprintf( stderr, "an error occured while using the portaudio stream\n" );
|
|
||||||
fprintf( stderr, "error number: %d\n", err );
|
|
||||||
fprintf( stderr, "error message: %s\n", Pa_GetErrorText( err ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
PaStreamParameters output_parameters;
|
|
||||||
output_parameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
|
|
||||||
if (output_parameters.device == paNoDevice) {
|
|
||||||
cerr<<"error: no default output device."<<endl;
|
|
||||||
}
|
|
||||||
output_parameters.channelCount = 2; /* stereo output */
|
|
||||||
output_parameters.sampleFormat = paFloat32; /* 32 bit floating point output */
|
|
||||||
output_parameters.suggestedLatency = Pa_GetDeviceInfo( output_parameters.device )->defaultLowOutputLatency;
|
|
||||||
output_parameters.hostApiSpecificStreamInfo = NULL;
|
|
||||||
|
|
||||||
PaStreamParameters input_parameters;
|
|
||||||
input_parameters.device = Pa_GetDefaultInputDevice(); /* default output device */
|
|
||||||
if (input_parameters.device == paNoDevice) {
|
|
||||||
cerr<<"error: no default input device."<<endl;
|
|
||||||
}
|
|
||||||
input_parameters.channelCount = 2; /* stereo output */
|
|
||||||
input_parameters.sampleFormat = paFloat32; /* 32 bit floating point output */
|
|
||||||
input_parameters.suggestedLatency = Pa_GetDeviceInfo( input_parameters.device )->defaultLowInputLatency;
|
|
||||||
input_parameters.hostApiSpecificStreamInfo = NULL;
|
|
||||||
|
|
||||||
PaStream *stream;
|
|
||||||
|
|
||||||
err = Pa_OpenStream(
|
|
||||||
&stream,
|
|
||||||
NULL, //&input_parameters,
|
|
||||||
&output_parameters,
|
|
||||||
dopt.samplerate,
|
|
||||||
dopt.buffer_size,
|
|
||||||
paClipOff,
|
|
||||||
process,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if( err != paNoError )
|
|
||||||
{
|
|
||||||
cerr<<"could not attach portaudio_client: "<<Pa_GetErrorText( err )<<endl;
|
|
||||||
Pa_Terminate();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = Pa_StartStream(stream);
|
|
||||||
|
|
||||||
if( err != paNoError )
|
|
||||||
{
|
|
||||||
cerr<<"could not start stream: "<<Pa_GetErrorText( err )<<endl;
|
|
||||||
Pa_Terminate();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_attached=true;
|
|
||||||
cerr<<"connected to portaudio..."<<endl;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void portaudio_client::detach()
|
|
||||||
{
|
|
||||||
cerr<<"detaching from portaudio"<<endl;
|
|
||||||
Pa_Terminate();
|
Pa_Terminate();
|
||||||
m_attached=false;
|
fprintf( stderr, "an error occured while using the portaudio stream\n" );
|
||||||
|
fprintf( stderr, "error number: %d\n", err );
|
||||||
|
fprintf( stderr, "error message: %s\n", Pa_GetErrorText( err ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
PaStreamParameters output_parameters;
|
||||||
|
output_parameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
|
||||||
|
if (output_parameters.device == paNoDevice) {
|
||||||
|
cerr<<"error: no default output device."<<endl;
|
||||||
|
}
|
||||||
|
output_parameters.channelCount = 2; /* stereo output */
|
||||||
|
output_parameters.sampleFormat = paFloat32; /* 32 bit floating point output */
|
||||||
|
output_parameters.suggestedLatency = Pa_GetDeviceInfo( output_parameters.device )->defaultLowOutputLatency;
|
||||||
|
output_parameters.hostApiSpecificStreamInfo = NULL;
|
||||||
|
|
||||||
|
PaStreamParameters input_parameters;
|
||||||
|
input_parameters.device = Pa_GetDefaultInputDevice(); /* default output device */
|
||||||
|
if (input_parameters.device == paNoDevice) {
|
||||||
|
cerr<<"error: no default input device."<<endl;
|
||||||
|
}
|
||||||
|
input_parameters.channelCount = 2; /* stereo output */
|
||||||
|
input_parameters.sampleFormat = paFloat32; /* 32 bit floating point output */
|
||||||
|
input_parameters.suggestedLatency = Pa_GetDeviceInfo( input_parameters.device )->defaultLowInputLatency;
|
||||||
|
input_parameters.hostApiSpecificStreamInfo = NULL;
|
||||||
|
|
||||||
|
PaStream *stream;
|
||||||
|
|
||||||
|
err = Pa_OpenStream(&stream,
|
||||||
|
&input_parameters,
|
||||||
|
&output_parameters,
|
||||||
|
dopt.samplerate,
|
||||||
|
dopt.buffer_size,
|
||||||
|
paClipOff,
|
||||||
|
process,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if(err != paNoError) {
|
||||||
|
cerr<<"could not attach portaudio_client: "<<Pa_GetErrorText( err )<<endl;
|
||||||
|
Pa_Terminate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = Pa_StartStream(stream);
|
||||||
|
|
||||||
|
if(err != paNoError) {
|
||||||
|
cerr<<"could not start stream: "<<Pa_GetErrorText( err )<<endl;
|
||||||
|
Pa_Terminate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_attached=true;
|
||||||
|
cerr<<"connected to portaudio..."<<endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void portaudio_client::detach() {
|
||||||
|
cerr<<"detaching from portaudio"<<endl;
|
||||||
|
Pa_Terminate();
|
||||||
|
m_attached=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int portaudio_client::process(const void *input_buffer, void *output_buffer,
|
int portaudio_client::process(const void *input_buffer, void *output_buffer,
|
||||||
unsigned long frames_per_buffer,
|
unsigned long frames_per_buffer,
|
||||||
const PaStreamCallbackTimeInfo* time_info,
|
const PaStreamCallbackTimeInfo* time_info,
|
||||||
PaStreamCallbackFlags status_flags,
|
PaStreamCallbackFlags status_flags,
|
||||||
void *user_data)
|
void *user_data) {
|
||||||
{
|
m_buffer_size=frames_per_buffer;
|
||||||
m_buffer_size=frames_per_buffer;
|
|
||||||
|
|
||||||
if(run_callback&&run_context)
|
if(run_callback&&run_context) {
|
||||||
{
|
// do the work
|
||||||
// do the work
|
run_callback(run_context, frames_per_buffer);
|
||||||
run_callback(run_context, frames_per_buffer);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (m_right_data && m_left_data)
|
if (m_right_data && m_left_data) {
|
||||||
{
|
float *out = (float*)output_buffer;
|
||||||
float *out = (float*)output_buffer;
|
for (unsigned int n=0; n<m_buffer_size; n++) {
|
||||||
for (unsigned int n=0; n<m_buffer_size; n++)
|
*out=m_left_data[n];
|
||||||
{
|
out++;
|
||||||
*out=m_left_data[n];
|
*out=m_right_data[n];
|
||||||
out++;
|
out++;
|
||||||
*out=m_right_data[n];
|
}
|
||||||
out++;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if (m_right_in_data && m_left_in_data)
|
if (m_right_in_data && m_left_in_data) {
|
||||||
{
|
float *in = (float*)input_buffer;
|
||||||
float *in = (float*)input_buffer;
|
for (unsigned int n=0; n<m_buffer_size; n++) {
|
||||||
for (unsigned int n=0; n<m_buffer_size; n++)
|
m_left_in_data[n]=*in;
|
||||||
{
|
in++;
|
||||||
m_left_in_data[n]=*in;
|
m_right_in_data[n]=*in;
|
||||||
in++;
|
in++;
|
||||||
m_right_in_data[n]=*in;
|
}
|
||||||
in++;
|
}
|
||||||
}
|
|
||||||
}*/
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
@ -27,49 +27,49 @@ using namespace std;
|
|||||||
|
|
||||||
class portaudio_client
|
class portaudio_client
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
portaudio_client();
|
portaudio_client();
|
||||||
~portaudio_client();
|
~portaudio_client();
|
||||||
|
|
||||||
class device_options
|
class device_options
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum type {READ,WRITE,READWRITE};
|
enum type {READ,WRITE,READWRITE};
|
||||||
unsigned int buffer_size;
|
unsigned int buffer_size;
|
||||||
unsigned int num_buffers;
|
unsigned int num_buffers;
|
||||||
unsigned int samplerate;
|
unsigned int samplerate;
|
||||||
unsigned int in_channels;
|
unsigned int in_channels;
|
||||||
unsigned int out_channels;
|
unsigned int out_channels;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool attach(const string &client_name, const device_options &dopt);
|
bool attach(const string &client_name, const device_options &dopt);
|
||||||
void detach();
|
void detach();
|
||||||
bool is_attached() { return m_attached; }
|
bool is_attached() { return m_attached; }
|
||||||
void set_callback(void(*run)(void*, unsigned int),void *context) { run_callback=run; run_context=context; }
|
void set_callback(void(*run)(void*, unsigned int),void *context) { run_callback=run; run_context=context; }
|
||||||
void set_outputs(const float *l, const float *r) { m_left_data=l; m_right_data=r; }
|
void set_outputs(const float *l, const float *r) { m_left_data=l; m_right_data=r; }
|
||||||
void set_inputs(float *l, float *r) { m_left_in_data=l; m_right_in_data=r; }
|
void set_inputs(float *l, float *r) { m_left_in_data=l; m_right_in_data=r; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
static int process(const void *input_buffer, void *output_buffer,
|
static int process(const void *input_buffer, void *output_buffer,
|
||||||
unsigned long frames_per_buffer,
|
unsigned long frames_per_buffer,
|
||||||
const PaStreamCallbackTimeInfo* time_info,
|
const PaStreamCallbackTimeInfo* time_info,
|
||||||
PaStreamCallbackFlags status_flags,
|
PaStreamCallbackFlags status_flags,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static long unsigned int m_buffer_size;
|
static long unsigned int m_buffer_size;
|
||||||
static long unsigned int m_sample_rate;
|
static long unsigned int m_sample_rate;
|
||||||
static bool m_attached;
|
static bool m_attached;
|
||||||
|
|
||||||
static const float *m_right_data;
|
static const float *m_right_data;
|
||||||
static const float *m_left_data;
|
static const float *m_left_data;
|
||||||
static float *m_right_in_data;
|
static float *m_right_in_data;
|
||||||
static float *m_left_in_data;
|
static float *m_left_in_data;
|
||||||
|
|
||||||
static void(*run_callback)(void *, unsigned int);
|
static void(*run_callback)(void *, unsigned int);
|
||||||
static void *run_context;
|
static void *run_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
// _copyright (_c) 2003 _david _griffiths <dave@pawfal.org>
|
// Copyright (C) 2003 Dave Griffiths
|
||||||
//
|
//
|
||||||
// _this program is free software; you can redistribute it and/or modify
|
// This program is free software; you can redistribute it and/or modify
|
||||||
// it under the terms of the _g_n_u _general _public _license as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the _free _software _foundation; either version 2 of the _license, or
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// _this program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but _w_i_t_h_o_u_t _a_n_y _w_a_r_r_a_n_t_y; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// _m_e_r_c_h_a_n_t_a_b_i_l_i_t_y or _f_i_t_n_e_s_s _f_o_r _a _p_a_r_t_i_c_u_l_a_r _p_u_r_p_o_s_e. _see the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// _g_n_u _general _public _license for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// _you should have received a copy of the _g_n_u _general _public _license
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program; if not, write to the _free _software
|
// along with this program; if not, write to the Free Software
|
||||||
// _foundation, _inc., 59 _temple _place - _suite 330, _boston, _m_a 02111-1307, _u_s_a.
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
@ -23,349 +24,313 @@ using namespace spiralcore;
|
|||||||
base_allocator *sample::m_allocator = new malloc_allocator();
|
base_allocator *sample::m_allocator = new malloc_allocator();
|
||||||
|
|
||||||
sample::sample(unsigned int len) :
|
sample::sample(unsigned int len) :
|
||||||
m_data(NULL),
|
m_data(NULL),
|
||||||
m_length(0)
|
m_length(0)
|
||||||
{
|
{
|
||||||
if (len)
|
if (len) {
|
||||||
{
|
allocate(len);
|
||||||
allocate(len);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sample::sample(const sample &rhs):
|
sample::sample(const sample &rhs):
|
||||||
m_data(NULL),
|
m_data(NULL),
|
||||||
m_length(0)
|
m_length(0)
|
||||||
{
|
{
|
||||||
*this=rhs;
|
*this=rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sample::sample(const audio_type *s, unsigned int len):
|
sample::sample(const audio_type *s, unsigned int len):
|
||||||
m_data(NULL),
|
m_data(NULL),
|
||||||
m_length(0)
|
m_length(0)
|
||||||
{
|
{
|
||||||
assert(s);
|
assert(s);
|
||||||
allocate(len);
|
allocate(len);
|
||||||
memcpy(m_data,s,get_length_in_bytes());
|
memcpy(m_data,s,get_length_in_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sample::~sample()
|
sample::~sample() {
|
||||||
{
|
clear();
|
||||||
clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool sample::allocate(unsigned int size)
|
bool sample::allocate(unsigned int size) {
|
||||||
{
|
clear();
|
||||||
clear();
|
|
||||||
|
|
||||||
m_data = (audio_type*) m_allocator->anew(size*sizeof(audio_type));
|
m_data = (audio_type*) m_allocator->anew(size*sizeof(audio_type));
|
||||||
m_length=size;
|
m_length=size;
|
||||||
|
|
||||||
memset(m_data,0,get_length_in_bytes());
|
memset(m_data,0,get_length_in_bytes());
|
||||||
|
|
||||||
return (m_data);
|
return (m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::clear()
|
void sample::clear() {
|
||||||
{
|
if (m_data) {
|
||||||
if (m_data)
|
m_allocator->adelete((char*)m_data);
|
||||||
{
|
m_length=0;
|
||||||
m_allocator->adelete((char*)m_data);
|
m_data=NULL;
|
||||||
m_length=0;
|
}
|
||||||
m_data=NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::zero()
|
void sample::zero() {
|
||||||
{
|
memset(m_data,0,get_length_in_bytes());
|
||||||
memset(m_data,0,get_length_in_bytes());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::set(audio_type val)
|
void sample::set(audio_type val) {
|
||||||
{
|
for (unsigned int n=0; n<m_length; n++) {
|
||||||
for (unsigned int n=0; n<m_length; n++)
|
m_data[n]=val;
|
||||||
{
|
}
|
||||||
m_data[n]=val;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::insert(const sample &s, unsigned int pos)
|
void sample::insert(const sample &s, unsigned int pos) {
|
||||||
{
|
// do some checking
|
||||||
// do some checking
|
assert(pos<=get_length());
|
||||||
assert(pos<=get_length());
|
|
||||||
|
|
||||||
unsigned int new_len = get_length()+s.get_length();
|
unsigned int new_len = get_length()+s.get_length();
|
||||||
audio_type *new_buf = (audio_type*) m_allocator->anew(new_len*sizeof(audio_type));
|
audio_type *new_buf = (audio_type*) m_allocator->anew(new_len*sizeof(audio_type));
|
||||||
unsigned int from_pos=0, to_pos=0, temp_buf_pos=0;
|
unsigned int from_pos=0, to_pos=0, temp_buf_pos=0;
|
||||||
|
|
||||||
while (from_pos<=get_length())
|
while (from_pos<=get_length()) {
|
||||||
{
|
if (from_pos==pos) {
|
||||||
if (from_pos==pos)
|
for (temp_buf_pos=0; temp_buf_pos<s.get_length(); temp_buf_pos++) {
|
||||||
{
|
new_buf[to_pos]=s[temp_buf_pos];
|
||||||
for (temp_buf_pos=0; temp_buf_pos<s.get_length(); temp_buf_pos++)
|
to_pos++;
|
||||||
{
|
}
|
||||||
new_buf[to_pos]=s[temp_buf_pos];
|
} else {
|
||||||
to_pos++;
|
// this test is needed so the loop can deal
|
||||||
}
|
// with samples being "inserted" on to the
|
||||||
}
|
// very end of the buffer
|
||||||
else
|
if (from_pos<get_length()) {
|
||||||
{
|
new_buf[to_pos]=m_data[from_pos];
|
||||||
// this test is needed so the loop can deal
|
}
|
||||||
// with samples being "inserted" on to the
|
}
|
||||||
// very end of the buffer
|
from_pos++;
|
||||||
if (from_pos<get_length())
|
to_pos++;
|
||||||
{
|
}
|
||||||
new_buf[to_pos]=m_data[from_pos];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
from_pos++;
|
|
||||||
to_pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
m_data=new_buf;
|
m_data=new_buf;
|
||||||
m_length=new_len;
|
m_length=new_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::add(const sample &s)
|
void sample::add(const sample &s) {
|
||||||
{
|
insert(s,get_length());
|
||||||
insert(s,get_length());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::mix(const sample &s, unsigned int pos)
|
void sample::mix(const sample &s, unsigned int pos) {
|
||||||
{
|
// do some checking
|
||||||
// do some checking
|
assert(pos<get_length());
|
||||||
assert(pos<get_length());
|
|
||||||
|
|
||||||
unsigned int to_pos=pos;
|
unsigned int to_pos=pos;
|
||||||
|
|
||||||
for (unsigned int from_pos=0; from_pos<s.get_length(); from_pos++)
|
for (unsigned int from_pos=0; from_pos<s.get_length(); from_pos++) {
|
||||||
{
|
m_data[to_pos]=m_data[to_pos]+s[from_pos];
|
||||||
m_data[to_pos]=m_data[to_pos]+s[from_pos];
|
|
||||||
|
if (to_pos>get_length()) to_pos=0;
|
||||||
if (to_pos>get_length()) to_pos=0;
|
to_pos++;
|
||||||
to_pos++;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::mul_mix(const sample &s, unsigned int pos, float m)
|
void sample::mul_mix(const sample &s, unsigned int pos, float m) {
|
||||||
{
|
// do some checking
|
||||||
// do some checking
|
assert(pos<get_length());
|
||||||
assert(pos<get_length());
|
|
||||||
|
|
||||||
unsigned int to_pos=pos;
|
unsigned int to_pos=pos;
|
||||||
|
|
||||||
for (unsigned int from_pos=0; from_pos<s.get_length(); from_pos++)
|
for (unsigned int from_pos=0; from_pos<s.get_length(); from_pos++) {
|
||||||
{
|
m_data[to_pos]=m_data[to_pos]+s[from_pos]*m;
|
||||||
m_data[to_pos]=m_data[to_pos]+s[from_pos]*m;
|
|
||||||
|
if (to_pos>get_length()) to_pos=0;
|
||||||
if (to_pos>get_length()) to_pos=0;
|
to_pos++;
|
||||||
to_pos++;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::mul_clip_mix(const sample &s, float m)
|
void sample::mul_clip_mix(const sample &s, float m) {
|
||||||
{
|
unsigned int to_pos=0;
|
||||||
unsigned int to_pos=0;
|
|
||||||
|
for (unsigned int from_pos=0; from_pos<s.get_length(); from_pos++) {
|
||||||
for (unsigned int from_pos=0; from_pos<s.get_length(); from_pos++)
|
float t=s[from_pos]*m;
|
||||||
{
|
if (t>m) t=m;
|
||||||
float t=s[from_pos]*m;
|
else if (t<-m) t=-m;
|
||||||
if (t>m) t=m;
|
|
||||||
else if (t<-m) t=-m;
|
m_data[to_pos]=m_data[to_pos]+t;
|
||||||
|
|
||||||
m_data[to_pos]=m_data[to_pos]+t;
|
if (to_pos>get_length()) to_pos=0;
|
||||||
|
to_pos++;
|
||||||
if (to_pos>get_length()) to_pos=0;
|
}
|
||||||
to_pos++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::remove(unsigned int start, unsigned int end)
|
void sample::remove(unsigned int start, unsigned int end) {
|
||||||
{
|
// do some checking
|
||||||
// do some checking
|
assert(end<get_length() && start<get_length());
|
||||||
assert(end<get_length() && start<get_length());
|
assert(start<=end);
|
||||||
assert(start<=end);
|
|
||||||
|
|
||||||
// check the range
|
// check the range
|
||||||
if (end>get_length()) end=get_length();
|
if (end>get_length()) end=get_length();
|
||||||
// unsigned, impossible
|
// unsigned, impossible
|
||||||
//if (start<0) start=0;
|
//if (start<0) start=0;
|
||||||
|
|
||||||
// calc lengths and allocate memory
|
// calc lengths and allocate memory
|
||||||
unsigned int cut_len = end - start;
|
unsigned int cut_len = end - start;
|
||||||
// has to be granulated by the buffer size
|
// has to be granulated by the buffer size
|
||||||
|
|
||||||
unsigned int new_len = get_length()-cut_len;
|
unsigned int new_len = get_length()-cut_len;
|
||||||
|
|
||||||
audio_type *temp_buf = (audio_type*) m_allocator->anew(new_len*sizeof(audio_type));
|
audio_type *temp_buf = (audio_type*) m_allocator->anew(new_len*sizeof(audio_type));
|
||||||
|
|
||||||
unsigned int to_pos=0;
|
unsigned int to_pos=0;
|
||||||
|
|
||||||
for (unsigned int from_pos=0; from_pos<get_length(); from_pos++)
|
for (unsigned int from_pos=0; from_pos<get_length(); from_pos++) {
|
||||||
{
|
// copy the areas outside of the cut range
|
||||||
// copy the areas outside of the cut range
|
if (from_pos<start || from_pos>end) {
|
||||||
if (from_pos<start || from_pos>end)
|
temp_buf[to_pos]=m_data[from_pos];
|
||||||
{
|
to_pos++;
|
||||||
temp_buf[to_pos]=m_data[from_pos];
|
// check the position is in range of the calculated length
|
||||||
to_pos++;
|
assert(to_pos<=new_len);
|
||||||
// check the position is in range of the calculated length
|
}
|
||||||
assert(to_pos<=new_len);
|
}
|
||||||
}
|
|
||||||
}
|
clear();
|
||||||
|
m_data=temp_buf;
|
||||||
clear();
|
m_length=new_len;
|
||||||
m_data=temp_buf;
|
|
||||||
m_length=new_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::reverse(unsigned int start, unsigned int end)
|
void sample::reverse(unsigned int start, unsigned int end) {
|
||||||
{
|
// do some checking
|
||||||
// do some checking
|
assert(end<get_length() && start<get_length());
|
||||||
assert(end<get_length() && start<get_length());
|
assert(start<=end);
|
||||||
assert(start<=end);
|
|
||||||
|
|
||||||
// check the range
|
// check the range
|
||||||
if (end>get_length()) end=get_length();
|
if (end>get_length()) end=get_length();
|
||||||
|
|
||||||
unsigned int new_len = end-start;
|
unsigned int new_len = end-start;
|
||||||
audio_type *temp_buf = (audio_type*) m_allocator->anew(new_len*sizeof(audio_type));
|
audio_type *temp_buf = (audio_type*) m_allocator->anew(new_len*sizeof(audio_type));
|
||||||
unsigned int to_pos=0;
|
unsigned int to_pos=0;
|
||||||
unsigned int from_pos=0;
|
unsigned int from_pos=0;
|
||||||
|
|
||||||
// get the reversed sample
|
// get the reversed sample
|
||||||
for (from_pos=end; from_pos>start; from_pos--)
|
for (from_pos=end; from_pos>start; from_pos--) {
|
||||||
{
|
temp_buf[to_pos]=m_data[from_pos];
|
||||||
temp_buf[to_pos]=m_data[from_pos];
|
to_pos++;
|
||||||
to_pos++;
|
assert(to_pos<=new_len);
|
||||||
assert(to_pos<=new_len);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
from_pos=0;
|
from_pos=0;
|
||||||
|
|
||||||
// overwrite back into place
|
// overwrite back into place
|
||||||
for (to_pos=start; to_pos<end; to_pos++)
|
for (to_pos=start; to_pos<end; to_pos++) {
|
||||||
{
|
m_data[to_pos]=temp_buf[from_pos];
|
||||||
m_data[to_pos]=temp_buf[from_pos];
|
from_pos++;
|
||||||
from_pos++;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::move(unsigned int dist)
|
void sample::move(unsigned int dist) {
|
||||||
{
|
unsigned int length=get_length();
|
||||||
unsigned int length=get_length();
|
audio_type *temp_buf = (audio_type*) m_allocator->anew(length*sizeof(audio_type));
|
||||||
audio_type *temp_buf = (audio_type*) m_allocator->anew(length*sizeof(audio_type));
|
unsigned int to_pos=0;
|
||||||
unsigned int to_pos=0;
|
unsigned int from_pos=dist;
|
||||||
unsigned int from_pos=dist;
|
|
||||||
|
|
||||||
// unsigned - impossible
|
// unsigned - impossible
|
||||||
//if (from_pos<0) from_pos+=length;
|
//if (from_pos<0) from_pos+=length;
|
||||||
if (from_pos>length) from_pos-=length;
|
if (from_pos>length) from_pos-=length;
|
||||||
|
|
||||||
// get the offset sample
|
// get the offset sample
|
||||||
for (to_pos=0; to_pos<length; to_pos++)
|
for (to_pos=0; to_pos<length; to_pos++) {
|
||||||
{
|
temp_buf[to_pos]=m_data[from_pos];
|
||||||
temp_buf[to_pos]=m_data[from_pos];
|
from_pos++;
|
||||||
from_pos++;
|
if (from_pos>=length) from_pos=0;
|
||||||
if (from_pos>=length) from_pos=0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
m_data=temp_buf;
|
m_data=temp_buf;
|
||||||
m_length=length;
|
m_length=length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::get_region(sample &s, unsigned int start, unsigned int end) const
|
// will wrap with minus start index
|
||||||
{
|
void sample::get_region(sample &s, int start, unsigned int end) const {
|
||||||
// do some checking
|
// do some checking
|
||||||
assert(end<get_length() && start<get_length());
|
assert(end<get_length() && start<(s32)get_length());
|
||||||
assert(start<=end);
|
assert(start<=(s32)end);
|
||||||
|
|
||||||
unsigned int length=end-start;
|
unsigned int length=end-start;
|
||||||
s.allocate(length);
|
s.allocate(length);
|
||||||
|
|
||||||
unsigned int from_pos=start;
|
unsigned int from_pos=start;
|
||||||
|
|
||||||
for (unsigned int to_pos=0; to_pos<length; to_pos++)
|
for (unsigned int to_pos=0; to_pos<length; to_pos++) {
|
||||||
{
|
s.set(to_pos,wrapped_get(from_pos));
|
||||||
s.set(to_pos,m_data[from_pos]);
|
from_pos++;
|
||||||
from_pos++;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::crop_to(unsigned int new_length)
|
void sample::crop_to(unsigned int new_length) {
|
||||||
{
|
assert (new_length<get_length());
|
||||||
assert (new_length<get_length());
|
|
||||||
|
|
||||||
audio_type *temp = (audio_type*) m_allocator->anew(new_length*sizeof(audio_type));
|
audio_type *temp = (audio_type*) m_allocator->anew(new_length*sizeof(audio_type));
|
||||||
|
|
||||||
for(unsigned int n=0; n<new_length; n++)
|
for(unsigned int n=0; n<new_length; n++) {
|
||||||
{
|
temp[n]=m_data[n];
|
||||||
temp[n]=m_data[n];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
m_data=temp;
|
m_data=temp;
|
||||||
m_length=new_length;
|
m_length=new_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// adds length amount of blank space
|
// adds length amount of blank space
|
||||||
void sample::expand(unsigned int length)
|
void sample::expand(unsigned int length) {
|
||||||
{
|
sample temp(length);
|
||||||
sample temp(length);
|
temp.zero();
|
||||||
temp.zero();
|
|
||||||
|
|
||||||
add(temp);
|
add(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// shrink the samle by length amount
|
// shrink the samle by length amount
|
||||||
void sample::shrink(unsigned int length)
|
void sample::shrink(unsigned int length) {
|
||||||
{
|
unsigned int new_length=get_length()-length;
|
||||||
unsigned int new_length=get_length()-length;
|
assert(new_length>0 && new_length<=get_length());
|
||||||
assert(new_length>0 && new_length<=get_length());
|
|
||||||
|
|
||||||
audio_type *temp = (audio_type*) m_allocator->anew(new_length*sizeof(audio_type));
|
audio_type *temp = (audio_type*) m_allocator->anew(new_length*sizeof(audio_type));
|
||||||
|
|
||||||
for(unsigned int n=0; n<new_length; n++)
|
for(unsigned int n=0; n<new_length; n++) {
|
||||||
{
|
temp[n]=m_data[n];
|
||||||
temp[n]=m_data[n];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
m_data=temp;
|
m_data=temp;
|
||||||
m_length=new_length;
|
m_length=new_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
ios &spiralcore::operator||(ios &s, sample &sa) {
|
ios &spiralcore::operator||(ios &s, sample &sa) {
|
||||||
unsigned int version=1;
|
unsigned int version=1;
|
||||||
string id("sample");
|
string id("sample");
|
||||||
s||id||version;
|
s||id||version;
|
||||||
s||sa.m_sample_type;
|
s||sa.m_sample_type;
|
||||||
|
|
||||||
ofstream *pos=dynamic_cast<ofstream*>(&s);
|
ofstream *pos=dynamic_cast<ofstream*>(&s);
|
||||||
if (pos!=NULL) {
|
if (pos!=NULL) {
|
||||||
ofstream &os = *pos;
|
ofstream &os = *pos;
|
||||||
size_t len = sa.m_length;
|
size_t len = sa.m_length;
|
||||||
os.write((char*)&len,sizeof(size_t));
|
os.write((char*)&len,sizeof(size_t));
|
||||||
os.write((char*)sa.m_data,sa.m_length*sizeof(audio_type));
|
os.write((char*)sa.m_data,sa.m_length*sizeof(audio_type));
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ifstream *pis=dynamic_cast<ifstream*>(&s);
|
ifstream *pis=dynamic_cast<ifstream*>(&s);
|
||||||
assert(pis!=NULL);
|
assert(pis!=NULL);
|
||||||
ifstream &is = *pis;
|
ifstream &is = *pis;
|
||||||
size_t len=0;
|
size_t len=0;
|
||||||
is.read((char *)&len,sizeof(size_t));
|
is.read((char *)&len,sizeof(size_t));
|
||||||
float *data = new float[len];
|
float *data = new float[len];
|
||||||
is.read((char*)data,len*sizeof(audio_type));
|
is.read((char*)data,len*sizeof(audio_type));
|
||||||
sa.m_data = data;
|
sa.m_data = data;
|
||||||
sa.m_length = len;
|
sa.m_length = len;
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,102 +32,101 @@ namespace spiralcore
|
|||||||
{
|
{
|
||||||
//#define DEBUG
|
//#define DEBUG
|
||||||
|
|
||||||
inline float linear(float bot,float top,float pos,float val1,float val2)
|
inline float linear(float bot,float top,float pos,float val1,float val2) {
|
||||||
{
|
|
||||||
float t=(pos-bot)/(top-bot);
|
float t=(pos-bot)/(top-bot);
|
||||||
return val1*t + val2*(1.0f-t);
|
return val1*t + val2*(1.0f-t);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool feq(float a, float b, float tol=0.00001)
|
inline bool feq(float a, float b, float tol=0.00001) {
|
||||||
{
|
return (a>b-tol && a<b+tol);
|
||||||
return (a>b-tol && a<b+tol);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class sample
|
class sample
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum sample_type {AUDIO=0, IMAGE, MIDI};
|
enum sample_type {AUDIO=0, IMAGE, MIDI};
|
||||||
|
|
||||||
sample(unsigned int len=0);
|
sample(unsigned int len=0);
|
||||||
sample(const sample &rhs);
|
sample(const sample &rhs);
|
||||||
sample(const audio_type *s, unsigned int len);
|
sample(const audio_type *s, unsigned int len);
|
||||||
~sample();
|
~sample();
|
||||||
|
|
||||||
static void set_allocator(base_allocator *s) { m_allocator=s; }
|
static void set_allocator(base_allocator *s) { m_allocator=s; }
|
||||||
static base_allocator *get_allocator() { return m_allocator; }
|
static base_allocator *get_allocator() { return m_allocator; }
|
||||||
|
|
||||||
bool allocate(unsigned int size);
|
bool allocate(unsigned int size);
|
||||||
void clear();
|
void clear();
|
||||||
void zero();
|
void zero();
|
||||||
void set(audio_type val);
|
void set(audio_type val);
|
||||||
void insert(const sample &s, unsigned int pos);
|
void insert(const sample &s, unsigned int pos);
|
||||||
void add(const sample &s);
|
void add(const sample &s);
|
||||||
void mix(const sample &s, unsigned int pos=0);
|
void mix(const sample &s, unsigned int pos=0);
|
||||||
void mul_mix(const sample &s, unsigned int pos, float m);
|
void mul_mix(const sample &s, unsigned int pos, float m);
|
||||||
void mul_clip_mix(const sample &s, float m);
|
void mul_clip_mix(const sample &s, float m);
|
||||||
void remove(unsigned int start, unsigned int end);
|
void remove(unsigned int start, unsigned int end);
|
||||||
void reverse(unsigned int start, unsigned int end);
|
void reverse(unsigned int start, unsigned int end);
|
||||||
void move(unsigned int dist);
|
void move(unsigned int dist);
|
||||||
void get_region(sample &s, unsigned int start, unsigned int end) const;
|
// will wrap with minus start index
|
||||||
const audio_type *get_buffer() const {return m_data;}
|
void get_region(sample &s, int start, unsigned int end) const;
|
||||||
audio_type *get_non_const_buffer() {return m_data;}
|
const audio_type *get_buffer() const {return m_data;}
|
||||||
unsigned int get_length() const {return m_length;}
|
audio_type *get_non_const_buffer() {return m_data;}
|
||||||
unsigned int get_length_in_bytes() const {return m_length*sizeof(audio_type);}
|
unsigned int get_length() const {return m_length;}
|
||||||
void expand(unsigned int length);
|
unsigned int get_length_in_bytes() const {return m_length*sizeof(audio_type);}
|
||||||
void shrink(unsigned int length);
|
void expand(unsigned int length);
|
||||||
void crop_to(unsigned int new_length);
|
void shrink(unsigned int length);
|
||||||
|
void crop_to(unsigned int new_length);
|
||||||
|
|
||||||
audio_type &operator[](unsigned int i) const
|
audio_type &wrapped_get(int i) const {
|
||||||
{
|
return m_data[i%m_length];
|
||||||
#ifdef DEBUG
|
}
|
||||||
cerr<<"debug..."<<endl;
|
|
||||||
assert(i<m_length);
|
|
||||||
#endif
|
|
||||||
return m_data[i%m_length];
|
|
||||||
}
|
|
||||||
|
|
||||||
// _linear interpolated
|
audio_type &operator[](unsigned int i) const {
|
||||||
inline audio_type operator[](float i) const
|
#ifdef DEBUG
|
||||||
{
|
cerr<<"debug..."<<endl;
|
||||||
unsigned int ii=(unsigned int)i;
|
assert(i<m_length);
|
||||||
|
#endif
|
||||||
|
return m_data[i%m_length];
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
// linear interpolated
|
||||||
assert(ii<m_length);
|
inline audio_type operator[](float i) const {
|
||||||
#endif
|
unsigned int ii=(unsigned int)i;
|
||||||
|
|
||||||
if (ii==m_length-1) return m_data[ii%m_length];
|
#ifdef DEBUG
|
||||||
audio_type t=i-ii;
|
assert(ii<m_length);
|
||||||
return ((m_data[ii%m_length]*(1-t))+
|
#endif
|
||||||
(m_data[(ii+1)%m_length])*t);
|
|
||||||
}
|
if (ii==m_length-1) return m_data[ii%m_length];
|
||||||
|
audio_type t=i-ii;
|
||||||
|
return ((m_data[ii%m_length]*(1-t))+
|
||||||
|
(m_data[(ii+1)%m_length])*t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void set(unsigned int i, audio_type v)
|
void set(unsigned int i, audio_type v) {
|
||||||
{
|
#ifdef DEBUG
|
||||||
#ifdef DEBUG
|
assert(i<m_length);
|
||||||
assert(i<m_length);
|
#endif
|
||||||
#endif
|
m_data[i%m_length]=v;
|
||||||
m_data[i%m_length]=v;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
sample &operator=(const sample &rhs)
|
sample &operator=(const sample &rhs) {
|
||||||
{
|
if (get_length()!=rhs.get_length()) allocate(rhs.get_length());
|
||||||
if (get_length()!=rhs.get_length()) allocate(rhs.get_length());
|
memcpy(m_data,rhs.get_buffer(),get_length_in_bytes());
|
||||||
memcpy(m_data,rhs.get_buffer(),get_length_in_bytes());
|
return *this;
|
||||||
return *this;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
friend ios &operator||(ios &s, sample &sa);
|
friend ios &operator||(ios &s, sample &sa);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
audio_type *m_data;
|
audio_type *m_data;
|
||||||
unsigned int m_length;
|
unsigned int m_length;
|
||||||
|
|
||||||
sample_type m_sample_type;
|
sample_type m_sample_type;
|
||||||
static base_allocator *m_allocator;
|
static base_allocator *m_allocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
ios &operator||(ios &s, sample &sa);
|
ios &operator||(ios &s, sample &sa);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
using namespace spiralcore;
|
||||||
|
|
||||||
pthread_mutex_t* m_fuz_mutex;
|
pthread_mutex_t* m_fuz_mutex;
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ void fuz() {
|
|||||||
search_params p(0.5,0,0,99,0);
|
search_params p(0.5,0,0,99,0);
|
||||||
|
|
||||||
cerr<<"starting"<<endl;
|
cerr<<"starting"<<endl;
|
||||||
fuz_new_brain(p);
|
//fuz_new_brain(p);
|
||||||
cerr<<"reloading brain"<<endl;
|
cerr<<"reloading brain"<<endl;
|
||||||
|
|
||||||
brain source;
|
brain source;
|
||||||
@ -166,7 +167,6 @@ void fuz() {
|
|||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cerr<<"switch"<<endl;
|
|
||||||
rr.get_params()->m_ratio=fuz_rr_f(0,1);
|
rr.get_params()->m_ratio=fuz_rr_f(0,1);
|
||||||
rr.get_params()->m_n_ratio=fuz_rr_f(0,1);
|
rr.get_params()->m_n_ratio=fuz_rr_f(0,1);
|
||||||
rr.get_params()->m_fft1_start=fuz_rr_i(0,49);
|
rr.get_params()->m_fft1_start=fuz_rr_i(0,49);
|
||||||
@ -190,7 +190,6 @@ void fuz() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
sleep(1);
|
sleep(1);
|
||||||
cerr<<counter<<endl;
|
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,6 +199,6 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
m_fuz_mutex = new pthread_mutex_t;
|
m_fuz_mutex = new pthread_mutex_t;
|
||||||
pthread_mutex_init(m_fuz_mutex,NULL);
|
pthread_mutex_init(m_fuz_mutex,NULL);
|
||||||
//unit_test();
|
unit_test();
|
||||||
fuz();
|
fuz();
|
||||||
}
|
}
|
||||||
|
@ -52,11 +52,28 @@ void renderer::reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void renderer::process(u32 nframes, float *buf) {
|
void renderer::process(u32 nframes, float *buf, const block_stream *bs) {
|
||||||
if (!m_playing) return;
|
// we can get blocks from the preprocessed target brain
|
||||||
if (!find_render_blocks(nframes)) return;
|
// or the realtime block stream
|
||||||
|
const block_source *source = (block_source*)bs;
|
||||||
|
if (source==NULL) {
|
||||||
|
cerr<<"not using block stream..."<<endl;
|
||||||
|
source = &m_target;
|
||||||
|
} else {
|
||||||
|
if (m_target_index<bs->last_block_index()-10) {
|
||||||
|
cerr<<"catch up..."<<endl;
|
||||||
|
m_target_index = bs->last_block_index();
|
||||||
|
}
|
||||||
|
if (m_target_index>bs->last_block_index()) {
|
||||||
|
cerr<<"catch down..."<<endl;
|
||||||
|
m_target_index = bs->last_block_index();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render(nframes,buf);
|
if (!m_playing) return;
|
||||||
|
if (!find_render_blocks(*source,nframes)) return;
|
||||||
|
|
||||||
|
render(*source,nframes,buf);
|
||||||
|
|
||||||
clean_up();
|
clean_up();
|
||||||
|
|
||||||
@ -67,19 +84,20 @@ void renderer::process(u32 nframes, float *buf) {
|
|||||||
// target_time = samples time into target stream
|
// target_time = samples time into target stream
|
||||||
// render_time = position in output stream, updated per process - used for offsets
|
// render_time = position in output stream, updated per process - used for offsets
|
||||||
|
|
||||||
bool renderer::find_render_blocks(u32 nframes) {
|
bool renderer::find_render_blocks(const block_source &target, u32 nframes) {
|
||||||
// get new blocks from source for the current buffer
|
// get new blocks from source for the current buffer
|
||||||
|
|
||||||
// where are we phase?
|
// figure out where are in the target blocks
|
||||||
u32 tgt_shift = m_target.get_block_size()-m_target.get_overlap();
|
u32 tgt_shift = target.get_block_size()-target.get_overlap();
|
||||||
m_target_index = m_target_time/(float)tgt_shift;
|
m_target_index = m_target_time/(float)tgt_shift;
|
||||||
u32 tgt_end = (m_target_time+nframes)/(float)tgt_shift;
|
u32 tgt_end = (m_target_time+nframes)/(float)tgt_shift;
|
||||||
|
// render end
|
||||||
u32 rnd_end = (m_render_time+nframes)/(float)tgt_shift;
|
u32 rnd_end = (m_render_time+nframes)/(float)tgt_shift;
|
||||||
|
|
||||||
|
// when stuff has changed, or we have fallen off the end
|
||||||
// stuff has changed - recompute and abort
|
// then recompute and abort
|
||||||
if (tgt_shift!=m_last_tgt_shift ||
|
if (tgt_shift!=m_last_tgt_shift ||
|
||||||
tgt_end>=m_target.get_num_blocks() ||
|
tgt_end>=target.get_num_blocks() ||
|
||||||
m_source.get_num_blocks()==0) {
|
m_source.get_num_blocks()==0) {
|
||||||
reset();
|
reset();
|
||||||
m_last_tgt_shift = tgt_shift;
|
m_last_tgt_shift = tgt_shift;
|
||||||
@ -87,7 +105,7 @@ bool renderer::find_render_blocks(u32 nframes) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
cerr<<"-----------------"<<endl;
|
cerr<<"-----------------"<<endl;
|
||||||
cerr<<"tgt start:"<<m_target_index<<endl;
|
cerr<<"tgt start:"<<m_target_index<<endl;
|
||||||
cerr<<"tgt end:"<<tgt_end<<endl;
|
cerr<<"tgt end:"<<tgt_end<<endl;
|
||||||
@ -99,7 +117,7 @@ bool renderer::find_render_blocks(u32 nframes) {
|
|||||||
cerr<<"render time (index) "<<m_render_index*tgt_shift<<endl;
|
cerr<<"render time (index) "<<m_render_index*tgt_shift<<endl;
|
||||||
cerr<<"real vs index = "<<(s32)m_render_time-(s32)(m_render_index*tgt_shift)<<endl;
|
cerr<<"real vs index = "<<(s32)m_render_time-(s32)(m_render_index*tgt_shift)<<endl;
|
||||||
cerr<<m_render_blocks.size()<<endl;
|
cerr<<m_render_blocks.size()<<endl;
|
||||||
*/
|
|
||||||
|
|
||||||
// search phase
|
// search phase
|
||||||
// get indices for current buffer
|
// get indices for current buffer
|
||||||
@ -109,22 +127,25 @@ bool renderer::find_render_blocks(u32 nframes) {
|
|||||||
u32 time=m_render_index*tgt_shift;
|
u32 time=m_render_index*tgt_shift;
|
||||||
u32 src_index=0;
|
u32 src_index=0;
|
||||||
|
|
||||||
|
// which algo are we using today?
|
||||||
switch (m_search_algo) {
|
switch (m_search_algo) {
|
||||||
case BASIC:
|
case BASIC:
|
||||||
src_index = m_source.search(m_target.get_block(m_target_index), m_search_params);
|
src_index = m_source.search(target.get_block(m_target_index), m_search_params);
|
||||||
break;
|
break;
|
||||||
case REV_BASIC:
|
case REV_BASIC:
|
||||||
src_index = m_source.rev_search(m_target.get_block(m_target_index), m_search_params);
|
src_index = m_source.rev_search(target.get_block(m_target_index), m_search_params);
|
||||||
break;
|
break;
|
||||||
case SYNAPTIC:
|
case SYNAPTIC:
|
||||||
case SYNAPTIC_SLIDE:
|
case SYNAPTIC_SLIDE:
|
||||||
src_index = m_source.search_synapses(m_target.get_block(m_target_index), m_search_params);
|
src_index = m_source.search_synapses(target.get_block(m_target_index), m_search_params);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_search_algo==SYNAPTIC_SLIDE) {
|
if (m_search_algo==SYNAPTIC_SLIDE) {
|
||||||
m_render_blocks.push_back(render_block(src_index,m_target_index,time));
|
m_render_blocks.push_back(render_block(src_index,m_target_index,time));
|
||||||
|
|
||||||
|
// synaptic slide blocks progression of the target until
|
||||||
|
// a good enough source block is found
|
||||||
if (m_source.get_current_error()<m_slide_error &&
|
if (m_source.get_current_error()<m_slide_error &&
|
||||||
m_render_index%m_stretch==0) {
|
m_render_index%m_stretch==0) {
|
||||||
m_target_index++;
|
m_target_index++;
|
||||||
@ -145,15 +166,16 @@ bool renderer::find_render_blocks(u32 nframes) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderer::render(u32 nframes, float *buf) {
|
void renderer::render(const block_source &target, u32 nframes, float *buf) {
|
||||||
sample render_pcm(m_source.get_block_size());
|
sample render_pcm(m_source.get_block_size());
|
||||||
|
|
||||||
// render phase
|
// render phase
|
||||||
// render all blocks in list
|
// render all blocks in list
|
||||||
for (std::list<render_block>::iterator i=m_render_blocks.begin(); i!=m_render_blocks.end(); ++i) {
|
for (std::list<render_block>::iterator i=m_render_blocks.begin(); i!=m_render_blocks.end(); ++i) {
|
||||||
|
// get all the pcm data now
|
||||||
const sample &pcm=m_source.get_block(i->m_index).get_pcm();
|
const sample &pcm=m_source.get_block(i->m_index).get_pcm();
|
||||||
const sample &n_pcm=m_source.get_block(i->m_index).get_n_pcm();
|
const sample &n_pcm=m_source.get_block(i->m_index).get_n_pcm();
|
||||||
const sample &target_pcm=m_target.get_block(i->m_tgt_index).get_pcm();
|
const sample &target_pcm=target.get_block(i->m_tgt_index).get_pcm();
|
||||||
// get the sample offset into the buffer
|
// get the sample offset into the buffer
|
||||||
s32 offset = i->m_time-m_render_time;
|
s32 offset = i->m_time-m_render_time;
|
||||||
|
|
||||||
@ -163,6 +185,7 @@ void renderer::render(u32 nframes, float *buf) {
|
|||||||
u32 block_start = offset;
|
u32 block_start = offset;
|
||||||
u32 buffer_start = 0;
|
u32 buffer_start = 0;
|
||||||
if (offset<0) {
|
if (offset<0) {
|
||||||
|
// it was running before this buffer
|
||||||
block_start=-offset;
|
block_start=-offset;
|
||||||
if (block_start>=block_length &&
|
if (block_start>=block_length &&
|
||||||
i->m_position>=block_length) {
|
i->m_position>=block_length) {
|
||||||
@ -177,20 +200,22 @@ void renderer::render(u32 nframes, float *buf) {
|
|||||||
// cerr<<"block start:"<<block_start<<endl;
|
// cerr<<"block start:"<<block_start<<endl;
|
||||||
// cerr<<"buffer start:"<<buffer_start<<endl;
|
// cerr<<"buffer start:"<<buffer_start<<endl;
|
||||||
|
|
||||||
|
|
||||||
// fade in/out autotune
|
// 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;
|
float pitch_scale = 1;
|
||||||
|
|
||||||
if (m_autotune>0) {
|
if (m_autotune>0) {
|
||||||
pitch_scale = m_target.get_block(i->m_tgt_index).get_freq() /
|
// scale by ratio between target and source
|
||||||
|
pitch_scale = target.get_block(i->m_tgt_index).get_freq() /
|
||||||
m_source.get_block(i->m_index).get_freq();
|
m_source.get_block(i->m_index).get_freq();
|
||||||
|
// restrict min/max pitch bend
|
||||||
float max = 1+(m_autotune*m_autotune)*100.0f;
|
float max = 1+(m_autotune*m_autotune)*100.0f;
|
||||||
if (pitch_scale>(max)) pitch_scale=max;
|
if (pitch_scale>(max)) pitch_scale=max;
|
||||||
if (pitch_scale<(1/max)) pitch_scale=1/max;
|
if (pitch_scale<(1/max)) pitch_scale=1/max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pitchshifting sounded rubbish with such small clips
|
||||||
//pitchshift::process(pcm,pitch_scale,render_pcm);
|
//pitchshift::process(pcm,pitch_scale,render_pcm);
|
||||||
|
|
||||||
if (!i->m_finished) {
|
if (!i->m_finished) {
|
||||||
@ -234,7 +259,7 @@ void renderer::render(u32 nframes, float *buf) {
|
|||||||
|
|
||||||
void renderer::clean_up() {
|
void renderer::clean_up() {
|
||||||
// cleanup phase
|
// cleanup phase
|
||||||
// delete old ones
|
// delete old render blocks that have finished
|
||||||
std::list<render_block>::iterator i=m_render_blocks.begin();
|
std::list<render_block>::iterator i=m_render_blocks.begin();
|
||||||
std::list<render_block>::iterator ni=m_render_blocks.begin();
|
std::list<render_block>::iterator ni=m_render_blocks.begin();
|
||||||
while(i!=m_render_blocks.end()) {
|
while(i!=m_render_blocks.end()) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <jellyfish/sample.h>
|
#include <jellyfish/sample.h>
|
||||||
#include "brain.h"
|
#include "brain.h"
|
||||||
|
#include "block_stream.h"
|
||||||
|
|
||||||
#ifndef SB_RENDERER
|
#ifndef SB_RENDERER
|
||||||
#define SB_RENDERER
|
#define SB_RENDERER
|
||||||
@ -42,8 +43,8 @@ namespace spiralcore {
|
|||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void process(u32 nframes, float *buf);
|
// block stream should be NULL if we are reading the target brain instead
|
||||||
void old_process(u32 nframes, float *buf);
|
void process(u32 nframes, float *buf, const block_stream *bs=NULL);
|
||||||
|
|
||||||
void set_search_algo(search_algo s) { m_search_algo=s; }
|
void set_search_algo(search_algo s) { m_search_algo=s; }
|
||||||
void set_playing(bool s) { m_playing=s; }
|
void set_playing(bool s) { m_playing=s; }
|
||||||
@ -71,8 +72,8 @@ namespace spiralcore {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool find_render_blocks(u32 nframes);
|
bool find_render_blocks(const block_source &target, u32 nframes);
|
||||||
void render(u32 nframes, float *buf);
|
void render(const block_source &target, u32 nframes, float *buf);
|
||||||
void clean_up();
|
void clean_up();
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user