added audio settings options for selection of device, samplrate and buffer size, also fixed: #65 & fixed: #64

This commit is contained in:
Dave Griffiths
2022-10-03 09:56:25 +01:00
parent fb8d607e2d
commit 4a4ab8b41a
19 changed files with 859 additions and 282 deletions

View File

@ -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) {
}

View File

@ -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);

View File

@ -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;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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);

View File

@ -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;
};