started making samplerate and buffer size configurable for audio device selection

This commit is contained in:
Dave Griffiths 2022-09-30 21:08:53 +01:00
parent a2b77951ca
commit fb8d607e2d
16 changed files with 112 additions and 124 deletions

View File

@ -26,7 +26,9 @@ audio_thread::audio_thread(process_thread &p) :
m_process_thread(p),
m_brain_mutex(p.m_brain_mutex),
m_stereo_mode(false),
m_mic_mode(false)
m_mic_mode(false),
m_bufsize(2048),
m_samplerate(44100)
{
start_audio();
pthread_mutex_lock(m_brain_mutex);
@ -48,8 +50,7 @@ audio_thread::~audio_thread() {
void audio_thread::start_audio() {
if (m_audio_device!=NULL) delete m_audio_device;
m_audio_device = new audio_device("samplebrain",48000,2048);
//m_audio_device = new audio_device("samplebrain",48000,2048*4);
m_audio_device = new audio_device("samplebrain",m_samplerate,m_bufsize);
m_audio_device->m_client.set_callback(run_audio, this);
}

View File

@ -24,8 +24,8 @@
namespace spiralcore {
class audio_thread {
public:
class audio_thread {
public:
audio_thread(process_thread &p);
~audio_thread();
@ -38,7 +38,7 @@ public:
renderer *m_right_renderer;
block_stream *m_block_stream;
private:
private:
void start_audio();
OSC_server m_osc;
@ -46,6 +46,8 @@ private:
pthread_mutex_t* m_brain_mutex;
bool m_stereo_mode;
bool m_mic_mode;
};
u32 m_bufsize;
u32 m_samplerate;
};
}

View File

@ -63,82 +63,82 @@ void process_thread::process() {
string name = cmd.m_name;
//cerr<<name<<endl;
if (name=="/load_sample") {
pthread_mutex_lock(m_brain_mutex);
m_source.load_sound(cmd.get_string(0),brain::MIX);
pthread_mutex_unlock(m_brain_mutex);
pthread_mutex_lock(m_brain_mutex);
m_source.load_sound(cmd.get_string(0),brain::MIX);
pthread_mutex_unlock(m_brain_mutex);
}
if (name=="/delete_sample") {
pthread_mutex_lock(m_brain_mutex);
m_source.delete_sound(cmd.get_string(0));
pthread_mutex_unlock(m_brain_mutex);
pthread_mutex_lock(m_brain_mutex);
m_source.delete_sound(cmd.get_string(0));
pthread_mutex_unlock(m_brain_mutex);
}
if (name=="/activate_sound") {
pthread_mutex_lock(m_brain_mutex);
m_source.activate_sound(cmd.get_string(0),1);
pthread_mutex_unlock(m_brain_mutex);
pthread_mutex_lock(m_brain_mutex);
m_source.activate_sound(cmd.get_string(0),1);
pthread_mutex_unlock(m_brain_mutex);
}
if (name=="/deactivate_sound") {
pthread_mutex_lock(m_brain_mutex);
m_source.activate_sound(cmd.get_string(0),0);
pthread_mutex_unlock(m_brain_mutex);
pthread_mutex_lock(m_brain_mutex);
m_source.activate_sound(cmd.get_string(0),0);
pthread_mutex_unlock(m_brain_mutex);
}
if (name=="/source_block_size") {
m_source_block_size = cmd.get_int(0);
m_source_block_size = cmd.get_int(0);
}
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") {
pthread_mutex_lock(m_brain_mutex);
m_source.init(m_source_block_size, m_source_overlap, m_window_type);
search_params p(1,0,0,100,0);
m_source.build_synapses_fixed(p);
m_left_renderer->reset();
m_right_renderer->reset();
pthread_mutex_unlock(m_brain_mutex);
pthread_mutex_lock(m_brain_mutex);
m_source.init(m_source_block_size, m_source_overlap, m_window_type);
search_params p(1,0,0,100,0);
m_source.build_synapses_fixed(p);
m_left_renderer->reset();
m_right_renderer->reset();
pthread_mutex_unlock(m_brain_mutex);
}
if (name=="/load_target") {
pthread_mutex_lock(m_brain_mutex);
m_left_target.clear_sounds();
m_left_target.load_sound(cmd.get_string(0),brain::LEFT);
m_right_target.clear_sounds();
m_right_target.load_sound(cmd.get_string(0),brain::RIGHT);
pthread_mutex_unlock(m_brain_mutex);
pthread_mutex_lock(m_brain_mutex);
m_left_target.clear_sounds();
m_left_target.load_sound(cmd.get_string(0),brain::LEFT);
m_right_target.clear_sounds();
m_right_target.load_sound(cmd.get_string(0),brain::RIGHT);
pthread_mutex_unlock(m_brain_mutex);
}
if (name=="/target_block_size") {
m_target_block_size = cmd.get_int(0);
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
m_target_block_size = cmd.get_int(0);
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
}
if (name=="/target_overlap") {
m_target_overlap = m_target_block_size*cmd.get_float(0);
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
m_target_overlap = m_target_block_size*cmd.get_float(0);
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
}
if (name=="/generate_target") {
pthread_mutex_lock(m_brain_mutex);
m_left_target.init(m_target_block_size, m_target_overlap, m_target_window_type);
m_right_target.init(m_target_block_size, m_target_overlap, m_target_window_type);
// probably elsewhere
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
pthread_mutex_unlock(m_brain_mutex);
pthread_mutex_lock(m_brain_mutex);
m_left_target.init(m_target_block_size, m_target_overlap, m_target_window_type);
m_right_target.init(m_target_block_size, m_target_overlap, m_target_window_type);
// probably elsewhere
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
pthread_mutex_unlock(m_brain_mutex);
}
if (name=="/window_type") {
m_window_type=(window::type)cmd.get_int(0);
m_window_type=(window::type)cmd.get_int(0);
}
if (name=="/target_window_type") {
m_target_window_type=(window::type)cmd.get_int(0);
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
m_target_window_type=(window::type)cmd.get_int(0);
m_block_stream->init(m_target_block_size, m_target_overlap, m_target_window_type);
}
if (name=="/load_brain") {
load_source(cmd.get_string(0));
load_source(cmd.get_string(0));
}
if (name=="/save_brain") {
save_source(cmd.get_string(0));
save_source(cmd.get_string(0));
}
if (name=="/load_session") {
load_session(cmd.get_string(0));
load_session(cmd.get_string(0));
}
if (name=="/save_session") {
save_session(cmd.get_string(0));
save_session(cmd.get_string(0));
}
}
#ifdef WIN32
@ -181,9 +181,6 @@ void process_thread::load_session(const std::string &filename) {
ifs||m_source_block_size||m_source_overlap;
ifs||m_target_block_size||m_target_overlap;
ifs||m_window_type||m_target_window_type;
cerr<<"loading window type session "<<m_target_window_type<<endl;
ifs||m_source;
ifs||m_left_target;
ifs||m_right_target;
@ -200,9 +197,6 @@ void process_thread::save_session(const std::string &filename) {
ofs||(*m_right_renderer);
ofs||m_source_block_size||m_source_overlap;
ofs||m_target_block_size||m_target_overlap;
cerr<<"saving window type session "<<m_target_window_type<<endl;
ofs||m_window_type||m_target_window_type;
ofs||m_source;
ofs||m_left_target;

View File

@ -77,7 +77,7 @@ block::block(u64 id, const string &filename, const sample &pcm, u32 rate, const
m_orig_filename(filename),
m_usage(0)
{
init_fft(m_pcm.get_length());
init_fft(m_pcm.get_length(),rate);
assert(m_mfcc_proc!=NULL);
assert(m_fftw!=NULL);
@ -97,12 +97,12 @@ 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, u32 rate) {
if (m_fftw == NULL || m_fftw->m_length!=block_size) {
if (m_fftw == NULL) delete m_fftw;
m_fftw = new FFT(block_size,100);
m_fftw = new FFT(block_size,rate,100);
if (m_mfcc_proc == NULL) delete m_mfcc_proc;
m_mfcc_proc = new Aquila::Mfcc(block_size);
m_mfcc_proc = new Aquila::Mfcc(block_size,rate);
}
}

View File

@ -38,7 +38,7 @@ namespace spiralcore {
// returns distance based on ratio of fft-mfcc values
double compare(const block &other, const search_params &params) const;
static void init_fft(u32 block_size);
static void init_fft(u32 block_size, u32 rate);
static bool unit_test();
const sample &get_pcm() const { return m_pcm; }

View File

@ -377,34 +377,6 @@ void brain::deplete_usage() {
}
}
// take another brain and rebuild this brain from bits of that one
// (presumably this one is made from a single sample)
/*void brain::resynth(const string &filename, const brain &other, const search_params &params){
sample out((m_block_size-m_overlap)*m_blocks.size());
out.zero();
u32 pos = 0;
u32 count = 0;
cerr<<other.m_blocks.size()<<" brain blocks..."<<endl;
cerr<<endl;
for (vector<block>::iterator i=m_blocks.begin(); i!=m_blocks.end(); ++i) {
cerr<<'\r';
cerr<<"searching: "<<count/float(m_blocks.size())*100;
u32 index = other.search(*i, params);
//cerr<<index<<endl;
out.mul_mix(other.get_block_pcm(index),pos,0.2);
if (count%1000==0) {
audio_device::save_sample(filename,out);
}
++count;
pos += (m_block_size-m_overlap);
}
audio_device::save_sample(filename,out);
}
*/
ios &spiralcore::operator||(ios &s, brain::sound &b) {
u32 version=1;
string id("brain::sound");

View File

@ -24,8 +24,9 @@ using namespace std;
static const int MAX_FFT_LENGTH = 4096;
FFT::FFT(u32 length, u32 bins) :
FFT::FFT(u32 length, u32 rate, u32 bins) :
m_length(length),
m_rate(rate),
m_num_bins(bins),
m_in(new double[length]),
m_spectrum(new fftw_complex[length]),
@ -35,26 +36,19 @@ FFT::FFT(u32 length, u32 bins) :
m_plan = fftw_plan_dft_r2c_1d(m_length, m_in, m_spectrum, FFTW_ESTIMATE);
}
FFT::~FFT()
{
FFT::~FFT() {
delete[] m_in;
fftw_destroy_plan(m_plan);
}
void FFT::impulse2freq(const float *imp)
{
void FFT::impulse2freq(const float *imp) {
unsigned int i;
for (i=0; i<m_length; i++)
{
m_in[i] = imp[i];
}
for (i=0; i<m_length; i++) {
m_in[i] = imp[i];
}
fftw_execute(m_plan);
}
static const float SRATE = 44100;
float FFT::calculate_dominant_freq() {
double highest = 0;
u32 index = 0;
@ -65,7 +59,7 @@ float FFT::calculate_dominant_freq() {
highest=t;
}
}
float freq = index * (SRATE/(float)m_length);
float freq = index * (m_rate/(float)m_length);
if (freq<0.01) freq=0.01;
return freq;
}

View File

@ -27,7 +27,7 @@ namespace spiralcore {
class FFT
{
public:
FFT(u32 length, u32 num_bins);
FFT(u32 length, u32 rate, u32 num_bins);
~FFT();
void impulse2freq(const float *imp);
void calculate_bins();
@ -35,6 +35,7 @@ namespace spiralcore {
fftw_plan m_plan;
u32 m_length;
u32 m_rate;
u32 m_num_bins;
double *m_in;
fftw_complex *m_spectrum;

View File

@ -26,7 +26,7 @@ namespace Aquila
{
//auto spectrum = m_fft->fft(source);
Aquila::MelFilterBank bank(44100, m_inputSize);
Aquila::MelFilterBank bank(m_sampleRate, m_inputSize);
auto filterOutput = bank.applyAll(spectrum);
Aquila::Dct dct;

View File

@ -59,8 +59,9 @@ namespace Aquila
*
* @param inputSize input length (common to all inputs)
*/
Mfcc(std::size_t inputSize):
m_inputSize(inputSize)//, m_fft(FftFactory::getFft(inputSize))
Mfcc(std::size_t inputSize, unsigned int sampleRate):
m_inputSize(inputSize), // m_fft(FftFactory::getFft(inputSize))
m_sampleRate(sampleRate)
{
}
@ -71,7 +72,8 @@ namespace Aquila
* Number of samples in each processed input.
*/
const std::size_t m_inputSize;
const unsigned int m_sampleRate;
/**
* FFT calculator.
*/

View File

@ -27,7 +27,8 @@ audio_device::audio_device(const string &clientname, u32 samplerate, u32 buffer_
left_in(buffer_size),
right_in(buffer_size),
m_recording(false),
m_record_filename("")
m_record_filename(""),
m_samplerate(samplerate)
{
portaudio_client::device_options opt;
opt.buffer_size = buffer_size;
@ -46,7 +47,7 @@ void audio_device::save_sample(const string &filename, const sample s) {
SF_INFO sfinfo;
sfinfo.format=SF_FORMAT_WAV | SF_FORMAT_FLOAT;
sfinfo.frames=s.get_length();
sfinfo.samplerate=44100;
sfinfo.samplerate=m_samplerate;
sfinfo.channels=1;
sfinfo.sections=1;
sfinfo.seekable=0;

View File

@ -24,8 +24,8 @@ class graph;
namespace spiralcore {
class audio_device {
public:
class audio_device {
public:
audio_device(const string &clientname, u32 samplerate, u32 buffer_size);
void start_graph(graph *graph);
@ -42,15 +42,15 @@ public:
portaudio_client m_client;
static void save_sample(const std::string &filename, const sample s);
void save_sample(const std::string &filename, const sample s);
private:
private:
bool m_recording;
std::string m_record_filename;
sample m_record_buffer_left;
sample m_record_buffer_right;
u32 m_record_counter;
};
u32 m_samplerate;
};
}

View File

@ -21,7 +21,6 @@
bool portaudio_client::m_attached = false;
long unsigned int portaudio_client::m_buffer_size = 0;
long unsigned int portaudio_client::m_sample_rate = 44100;
void (*portaudio_client::run_callback)(void*, unsigned int buf_size)=NULL;
void *portaudio_client::run_context = NULL;
const float *portaudio_client::m_right_data=NULL;
@ -42,6 +41,23 @@ portaudio_client::~portaudio_client() {
/////////////////////////////////////////////////////////////////////////////////////////////
vector<string> portaudio_client::sniff_devices() {
vector<string> ret;
int numDevices = Pa_GetDeviceCount();
if(numDevices < 0) {
// this is an error I guess
return ret;
}
const PaDeviceInfo *deviceInfo;
for(int i=0; i<numDevices; i++) {
deviceInfo = Pa_GetDeviceInfo(i);
ret.push_back(deviceInfo->name);
}
return ret;
}
/////////////////////////////////////////////////////////////////////////////////////////////
bool portaudio_client::attach(const string &client_name, const device_options &dopt) {
if (m_attached) return true;

View File

@ -42,6 +42,7 @@ class portaudio_client
unsigned int out_channels;
};
vector<string> sniff_devices();
bool attach(const string &client_name, const device_options &dopt);
void detach();
bool is_attached() { return m_attached; }
@ -60,7 +61,6 @@ class portaudio_client
private:
static long unsigned int m_buffer_size;
static long unsigned int m_sample_rate;
static bool m_attached;
static const float *m_right_data;

View File

@ -34,6 +34,10 @@ void status::sound_item_refresh() {
lo_send(m_address,"/sound-item-refresh","");
}
void status::add_audio_device(const std::string &name) {
lo_send(m_address,"/add_audio_device",name.c_str());
}
void status::update(const char *msg, ...) {
va_list args;
va_start(args, msg);

View File

@ -24,11 +24,12 @@ namespace spiralcore {
class status {
public:
static void _update(const std::string &msg);
static void update(const char *msg, ...);
static void sound_item(const std::string &name, const std::string &colour);
static void sound_item_refresh();
static lo_address m_address;
static void _update(const std::string &msg);
static void update(const char *msg, ...);
static void sound_item(const std::string &name, const std::string &colour);
static void sound_item_refresh();
static void add_audio_device(const std::string &name);
static lo_address m_address;
};
}