mirror of
https://gitlab.com/then-try-this/samplebrain.git
synced 2025-07-04 03:03:34 +00:00
added audio settings options for selection of device, samplrate and buffer size, also fixed: #65 & fixed: #64
This commit is contained in:
@ -22,25 +22,33 @@ using namespace std;
|
||||
using namespace spiralcore;
|
||||
|
||||
audio_device::audio_device(const string &clientname, u32 samplerate, u32 buffer_size) :
|
||||
left_out(buffer_size),
|
||||
right_out(buffer_size),
|
||||
left_in(buffer_size),
|
||||
right_in(buffer_size),
|
||||
m_recording(false),
|
||||
m_record_filename(""),
|
||||
m_samplerate(samplerate)
|
||||
{
|
||||
portaudio_client::device_options opt;
|
||||
opt.buffer_size = buffer_size;
|
||||
opt.num_buffers = 2;
|
||||
opt.samplerate = samplerate;
|
||||
opt.in_channels = 2;
|
||||
opt.out_channels = 2;
|
||||
m_samplerate(samplerate) {
|
||||
// connect to default device
|
||||
m_client.init();
|
||||
connect("", clientname, samplerate, buffer_size);
|
||||
}
|
||||
|
||||
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.attach(clientname,opt);
|
||||
void audio_device::connect(const string &output_device_name, const string &clientname, u32 samplerate, u32 buffer_size) {
|
||||
m_client.detach();
|
||||
|
||||
left_out.allocate(buffer_size);
|
||||
right_out.allocate(buffer_size);
|
||||
left_in.allocate(buffer_size);
|
||||
right_in.allocate(buffer_size);
|
||||
m_samplerate = samplerate;
|
||||
|
||||
portaudio_client::device_options opt;
|
||||
opt.buffer_size = buffer_size;
|
||||
opt.num_buffers = 2;
|
||||
opt.samplerate = samplerate;
|
||||
opt.in_channels = 2;
|
||||
opt.out_channels = 2;
|
||||
|
||||
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.attach(output_device_name,clientname,opt);
|
||||
}
|
||||
|
||||
void audio_device::save_sample(const string &filename, const sample s) {
|
||||
@ -83,5 +91,4 @@ void audio_device::maybe_record() {
|
||||
}
|
||||
}
|
||||
|
||||
void audio_device::start_graph(graph *graph) {
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace spiralcore {
|
||||
public:
|
||||
audio_device(const string &clientname, u32 samplerate, u32 buffer_size);
|
||||
|
||||
void start_graph(graph *graph);
|
||||
void connect(const string &output_device, const string &clientname, u32 samplerate, u32 buffer_size);
|
||||
|
||||
void start_recording(std::string filename);
|
||||
void stop_recording();
|
||||
@ -39,7 +39,7 @@ namespace spiralcore {
|
||||
sample left_in;
|
||||
sample right_in;
|
||||
graph *m_graph;
|
||||
|
||||
|
||||
portaudio_client m_client;
|
||||
|
||||
void save_sample(const std::string &filename, const sample s);
|
||||
|
@ -19,14 +19,16 @@
|
||||
|
||||
#include "portaudio_client.h"
|
||||
|
||||
bool portaudio_client::m_attached = false;
|
||||
long unsigned int portaudio_client::m_buffer_size = 0;
|
||||
bool portaudio_client::m_initialised = false;
|
||||
int portaudio_client::m_attached_device = -1;
|
||||
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;
|
||||
const float *portaudio_client::m_left_data=NULL;
|
||||
float *portaudio_client::m_right_in_data=NULL;
|
||||
float *portaudio_client::m_left_in_data=NULL;
|
||||
PaStream *portaudio_client::m_stream=NULL;
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
@ -36,75 +38,106 @@ portaudio_client::portaudio_client() {
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
portaudio_client::~portaudio_client() {
|
||||
detach();
|
||||
}
|
||||
|
||||
bool portaudio_client::init() {
|
||||
m_initialised=false;
|
||||
if (!m_initialised) {
|
||||
PaError err;
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) {
|
||||
Pa_Terminate();
|
||||
m_status="error initialising portaudio: "+string(Pa_GetErrorText(err))+"\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// load all the devices we have
|
||||
PaDeviceIndex default_output_num = Pa_GetDefaultOutputDevice();
|
||||
PaDeviceIndex default_input_num = Pa_GetDefaultInputDevice();
|
||||
|
||||
m_devices.clear();
|
||||
// get all devices we have available
|
||||
int numDevices = Pa_GetDeviceCount();
|
||||
if(numDevices <= 0) {
|
||||
m_status="portaudio error: no audio devices found";
|
||||
return false;
|
||||
}
|
||||
|
||||
const PaDeviceInfo *deviceInfo;
|
||||
|
||||
for(int i=0; i<numDevices; i++) {
|
||||
deviceInfo = Pa_GetDeviceInfo(i);
|
||||
if (deviceInfo->maxOutputChannels>=2) {
|
||||
device_desc desc;
|
||||
desc.name = deviceInfo->name;
|
||||
desc.id = i;
|
||||
desc.default_input = i==default_input_num;
|
||||
desc.default_output = i==default_output_num;
|
||||
m_devices.push_back(desc);
|
||||
}
|
||||
}
|
||||
|
||||
m_initialised=true;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int portaudio_client::device_name_to_id(const string &name) {
|
||||
for (auto &d:m_devices) {
|
||||
if (d.name==name) return d.id;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool portaudio_client::attach(const string &requested_output_device, const string &client_name, const device_options &dopt) {
|
||||
if (!init()) return false;
|
||||
detach();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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;
|
||||
|
||||
PaError err;
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) {
|
||||
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 ) );
|
||||
}
|
||||
|
||||
PaDeviceIndex output_device_num = Pa_GetDefaultOutputDevice();
|
||||
PaDeviceIndex input_device_num = Pa_GetDefaultInputDevice();
|
||||
|
||||
PaStreamParameters output_parameters;
|
||||
output_parameters.device = output_device_num;
|
||||
if (output_parameters.device == paNoDevice) {
|
||||
cerr<<"error: no default output device."<<endl;
|
||||
} else {
|
||||
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;
|
||||
cerr<<"Connecting to "<<Pa_GetDeviceInfo( output_parameters.device )->name<<" for output"<<endl;
|
||||
}
|
||||
|
||||
int requested_output_id = device_name_to_id(requested_output_device);
|
||||
|
||||
PaStreamParameters input_parameters;
|
||||
PaStreamParameters output_parameters;
|
||||
if (requested_output_device=="" || requested_output_id==-1) {
|
||||
// start up by connecting to the default one
|
||||
PaDeviceIndex default_output_num = Pa_GetDefaultOutputDevice();
|
||||
if (default_output_num == paNoDevice) {
|
||||
m_status="error: no default output device.";
|
||||
return false;
|
||||
} else {
|
||||
output_parameters.device = default_output_num;
|
||||
}
|
||||
} else {
|
||||
output_parameters.device = requested_output_id;
|
||||
}
|
||||
|
||||
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;
|
||||
m_status="connecting to "+string(Pa_GetDeviceInfo(output_parameters.device)->name)+" for output\n";
|
||||
|
||||
// turn off input for the moment, it's causing
|
||||
// too many cross platform security issues
|
||||
|
||||
/*PaStreamParameters input_parameters;
|
||||
PaStreamParameters *input_p=&input_parameters;
|
||||
input_parameters.device = input_device_num;
|
||||
if (true || input_parameters.device == paNoDevice) {
|
||||
cerr<<"error: no default input device."<<endl;
|
||||
input_p=0;
|
||||
} else {
|
||||
input_parameters.channelCount = 2; /* stereo output */
|
||||
input_parameters.sampleFormat = paFloat32; /* 32 bit floating point output */
|
||||
input_parameters.channelCount = 2;
|
||||
input_parameters.sampleFormat = paFloat32;
|
||||
input_parameters.suggestedLatency = Pa_GetDeviceInfo( input_parameters.device )->defaultLowInputLatency;
|
||||
input_parameters.hostApiSpecificStreamInfo = NULL;
|
||||
cerr<<"Connecting to "<<Pa_GetDeviceInfo( input_parameters.device )->name<<" for input"<<endl;
|
||||
}
|
||||
} */
|
||||
|
||||
PaStream *stream;
|
||||
|
||||
err = Pa_OpenStream(&stream,
|
||||
input_p,
|
||||
PaError err = Pa_OpenStream(&m_stream,
|
||||
NULL,
|
||||
&output_parameters,
|
||||
dopt.samplerate,
|
||||
dopt.buffer_size,
|
||||
@ -112,31 +145,38 @@ bool portaudio_client::attach(const string &client_name, const device_options &d
|
||||
process,
|
||||
NULL);
|
||||
|
||||
m_attached_device=output_parameters.device;
|
||||
|
||||
if(err != paNoError) {
|
||||
cerr<<"could not attach portaudio_client: "<<Pa_GetErrorText( err )<<endl;
|
||||
Pa_Terminate();
|
||||
m_status+="could not attach: "+string(Pa_GetErrorText(err))+"\n";
|
||||
detach();
|
||||
return false;
|
||||
}
|
||||
|
||||
err = Pa_StartStream(stream);
|
||||
err = Pa_StartStream(m_stream);
|
||||
|
||||
if(err != paNoError) {
|
||||
cerr<<"could not start stream: "<<Pa_GetErrorText( err )<<endl;
|
||||
Pa_Terminate();
|
||||
m_status+="could not start stream: "+string(Pa_GetErrorText(err))+"\n";
|
||||
detach();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_attached=true;
|
||||
cerr<<"connected to portaudio..."<<endl;
|
||||
m_status+="we are connected to portaudio!\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void portaudio_client::detach() {
|
||||
cerr<<"detaching from portaudio"<<endl;
|
||||
Pa_Terminate();
|
||||
m_attached=false;
|
||||
if (m_attached_device!=-1) {
|
||||
if (m_stream!=NULL) {
|
||||
Pa_CloseStream(m_stream);
|
||||
}
|
||||
m_stream=NULL;
|
||||
m_status+="detaching from portaudio\n";
|
||||
Pa_Terminate();
|
||||
m_attached_device=-1;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -30,9 +30,9 @@ class portaudio_client
|
||||
public:
|
||||
portaudio_client();
|
||||
~portaudio_client();
|
||||
bool init();
|
||||
|
||||
class device_options
|
||||
{
|
||||
class device_options {
|
||||
public:
|
||||
enum type {READ,WRITE,READWRITE};
|
||||
unsigned int buffer_size;
|
||||
@ -42,14 +42,25 @@ class portaudio_client
|
||||
unsigned int out_channels;
|
||||
};
|
||||
|
||||
vector<string> sniff_devices();
|
||||
bool attach(const string &client_name, const device_options &dopt);
|
||||
class device_desc {
|
||||
public:
|
||||
string name;
|
||||
int id;
|
||||
bool default_input;
|
||||
bool default_output;
|
||||
};
|
||||
|
||||
vector<portaudio_client::device_desc> m_devices;
|
||||
|
||||
bool attach(const string &requested_output_device, const string &client_name, const device_options &dopt);
|
||||
void detach();
|
||||
bool is_attached() { return m_attached; }
|
||||
bool is_attached() { return m_attached_device!=-1; }
|
||||
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_inputs(float *l, float *r) { m_left_in_data=l; m_right_in_data=r; }
|
||||
|
||||
string m_status;
|
||||
|
||||
protected:
|
||||
|
||||
static int process(const void *input_buffer, void *output_buffer,
|
||||
@ -60,16 +71,21 @@ class portaudio_client
|
||||
|
||||
private:
|
||||
|
||||
int device_name_to_id(const string &name);
|
||||
|
||||
static long unsigned int m_buffer_size;
|
||||
static bool m_attached;
|
||||
|
||||
static bool m_initialised;
|
||||
static int m_attached_device;
|
||||
|
||||
static const float *m_right_data;
|
||||
static const float *m_left_data;
|
||||
static float *m_right_in_data;
|
||||
static float *m_left_in_data;
|
||||
|
||||
|
||||
static void(*run_callback)(void *, unsigned int);
|
||||
static void *run_context;
|
||||
static PaStream *m_stream;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -34,10 +34,6 @@ 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);
|
||||
|
@ -28,7 +28,8 @@ public:
|
||||
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 void add_audio_device(int id, const std::string &name, bool default_output);
|
||||
static void audio_device_status(const std::string &status);
|
||||
static lo_address m_address;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user