add an option to select audio device

This commit is contained in:
tildearrow 2022-02-13 21:42:57 -05:00
parent d2d60c4f1a
commit 53482105dc
8 changed files with 119 additions and 40 deletions

View file

@ -26,6 +26,10 @@ bool TAAudio::setRun(bool run) {
return running; return running;
} }
std::vector<String> TAAudio::listAudioDevices() {
return std::vector<String>();
}
bool TAAudio::init(TAAudioDesc& request, TAAudioDesc& response) { bool TAAudio::init(TAAudioDesc& request, TAAudioDesc& response) {
response=request; response=request;
return true; return true;

View file

@ -1,4 +1,6 @@
#include <SDL_audio.h>
#include <string.h> #include <string.h>
#include <vector>
#include "../ta-log.h" #include "../ta-log.h"
#include "sdl.h" #include "sdl.h"
@ -49,15 +51,41 @@ bool TAAudioSDL::setRun(bool run) {
return running; return running;
} }
std::vector<String> TAAudioSDL::listAudioDevices() {
std::vector<String> ret;
if (!audioSysStarted) {
if (SDL_Init(SDL_INIT_AUDIO)<0) {
logE("could not initialize SDL to list audio devices\n");
} else {
audioSysStarted=true;
}
}
int count=SDL_GetNumAudioDevices(false);
if (count<0) return ret;
for (int i=0; i<count; i++) {
const char* devName=SDL_GetAudioDeviceName(i,false);
if (devName!=NULL) {
ret.push_back(String(devName));
}
}
return ret;
}
bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) { bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) {
if (initialized) { if (initialized) {
logE("audio already initialized\n"); logE("audio already initialized\n");
return false; return false;
} }
if (!audioSysStarted) {
if (SDL_Init(SDL_INIT_AUDIO)<0) { if (SDL_Init(SDL_INIT_AUDIO)<0) {
logE("could not initialize SDL\n"); logE("could not initialize SDL\n");
return false; return false;
} }
audioSysStarted=true;
}
desc=request; desc=request;
desc.outFormat=TA_AUDIO_FORMAT_F32; desc.outFormat=TA_AUDIO_FORMAT_F32;
@ -69,12 +97,13 @@ bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) {
ac.callback=taSDLProcess; ac.callback=taSDLProcess;
ac.userdata=this; ac.userdata=this;
ai=SDL_OpenAudioDevice(NULL,0,&ac,&ar,SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); ai=SDL_OpenAudioDevice(request.deviceName.empty()?NULL:request.deviceName.c_str(),0,&ac,&ar,SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
if (ai==0) { if (ai==0) {
logE("could not open audio device: %s\n",SDL_GetError()); logE("could not open audio device: %s\n",SDL_GetError());
return false; return false;
} }
desc.deviceName=request.deviceName;
desc.name=""; desc.name="";
desc.rate=ar.freq; desc.rate=ar.freq;
desc.inChans=0; desc.inChans=0;

View file

@ -4,6 +4,7 @@
class TAAudioSDL: public TAAudio { class TAAudioSDL: public TAAudio {
SDL_AudioSpec ac, ar; SDL_AudioSpec ac, ar;
SDL_AudioDeviceID ai; SDL_AudioDeviceID ai;
bool audioSysStarted;
public: public:
void onProcess(unsigned char* buf, int nframes); void onProcess(unsigned char* buf, int nframes);
@ -11,5 +12,8 @@ class TAAudioSDL: public TAAudio {
void* getContext(); void* getContext();
bool quit(); bool quit();
bool setRun(bool run); bool setRun(bool run);
std::vector<String> listAudioDevices();
bool init(TAAudioDesc& request, TAAudioDesc& response); bool init(TAAudioDesc& request, TAAudioDesc& response);
TAAudioSDL():
audioSysStarted(false) {}
}; };

View file

@ -31,7 +31,7 @@ enum TAAudioFormat {
}; };
struct TAAudioDesc { struct TAAudioDesc {
String name; String name, deviceName;
double rate; double rate;
unsigned int bufsize, fragments; unsigned int bufsize, fragments;
unsigned char inChans, outChans; unsigned char inChans, outChans;
@ -46,40 +46,6 @@ struct TAAudioDesc {
outFormat(TA_AUDIO_FORMAT_F32) {} outFormat(TA_AUDIO_FORMAT_F32) {}
}; };
class TAAudio {
protected:
TAAudioDesc desc;
TAAudioFormat outFormat;
bool running, initialized;
float** inBufs;
float** outBufs;
void (*audioProcCallback)(void*,float**,float**,int,int,unsigned int);
void* audioProcCallbackUser;
void (*sampleRateChanged)(SampleRateChangeEvent);
void (*bufferSizeChanged)(BufferSizeChangeEvent);
public:
void setSampleRateChangeCallback(void (*callback)(SampleRateChangeEvent));
void setBufferSizeChangeCallback(void (*callback)(BufferSizeChangeEvent));
void setCallback(void (*callback)(void*,float**,float**,int,int,unsigned int), void* user);
virtual void* getContext();
virtual bool quit();
virtual bool setRun(bool run);
virtual bool init(TAAudioDesc& request, TAAudioDesc& response);
TAAudio():
outFormat(TA_AUDIO_FORMAT_F32),
running(false),
initialized(false),
inBufs(NULL),
outBufs(NULL),
audioProcCallback(NULL),
sampleRateChanged(NULL),
bufferSizeChanged(NULL) {}
virtual ~TAAudio();
};
enum TAMidiMessageTypes { enum TAMidiMessageTypes {
TA_MIDI_NOTE_OFF=0x80, TA_MIDI_NOTE_OFF=0x80,
@ -146,7 +112,42 @@ class TAMidiOut {
class TAMidi { class TAMidi {
std::vector<TAMidiIn*> in; std::vector<TAMidiIn*> in;
std::vector<TAMidiOut*> out; std::vector<TAMidiOut*> out;
};
class TAAudio {
protected:
TAAudioDesc desc;
TAAudioFormat outFormat;
bool running, initialized;
float** inBufs;
float** outBufs;
void (*audioProcCallback)(void*,float**,float**,int,int,unsigned int);
void* audioProcCallbackUser;
void (*sampleRateChanged)(SampleRateChangeEvent);
void (*bufferSizeChanged)(BufferSizeChangeEvent);
public:
TAMidi* midi;
void setSampleRateChangeCallback(void (*callback)(SampleRateChangeEvent));
void setBufferSizeChangeCallback(void (*callback)(BufferSizeChangeEvent));
void setCallback(void (*callback)(void*,float**,float**,int,int,unsigned int), void* user);
virtual void* getContext();
virtual bool quit();
virtual bool setRun(bool run);
virtual std::vector<String> listAudioDevices();
virtual bool init(TAAudioDesc& request, TAAudioDesc& response);
TAAudio():
outFormat(TA_AUDIO_FORMAT_F32),
running(false),
initialized(false),
inBufs(NULL),
outBufs(NULL),
audioProcCallback(NULL),
sampleRateChanged(NULL),
bufferSizeChanged(NULL) {}
virtual ~TAAudio();
}; };
#endif #endif

View file

@ -6181,6 +6181,17 @@ TAAudioDesc& DivEngine::getAudioDescGot() {
return got; return got;
} }
std::vector<String>& DivEngine::getAudioDevices() {
return audioDevs;
}
void DivEngine::rescanAudioDevices() {
audioDevs.clear();
if (output!=NULL) {
audioDevs=output->listAudioDevices();
}
}
void DivEngine::initDispatch() { void DivEngine::initDispatch() {
isBusy.lock(); isBusy.lock();
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
@ -6285,6 +6296,10 @@ bool DivEngine::initAudioBackend() {
logE("invalid audio engine!\n"); logE("invalid audio engine!\n");
return false; return false;
} }
audioDevs=output->listAudioDevices();
want.deviceName=getConfString("audioDevice","");
want.bufsize=getConfInt("audioBufSize",1024); want.bufsize=getConfInt("audioBufSize",1024);
want.rate=getConfInt("audioRate",44100); want.rate=getConfInt("audioRate",44100);
want.fragments=2; want.fragments=2;

View file

@ -169,6 +169,7 @@ class DivEngine {
String configFile; String configFile;
String lastError; String lastError;
String warnings; String warnings;
std::vector<String> audioDevs;
struct SamplePreview { struct SamplePreview {
int sample; int sample;
@ -505,6 +506,12 @@ class DivEngine {
// set the view mode. // set the view mode.
void setView(DivStatusView which); void setView(DivStatusView which);
// get available audio devices
std::vector<String>& getAudioDevices();
// rescan audio devices
void rescanAudioDevices();
// set the console mode. // set the console mode.
void setConsoleMode(bool enable); void setConsoleMode(bool enable);

View file

@ -3769,6 +3769,21 @@ void FurnaceGUI::drawSettings() {
ImGui::SameLine(); ImGui::SameLine();
ImGui::Combo("##Backend",&settings.audioEngine,audioBackends,2); ImGui::Combo("##Backend",&settings.audioEngine,audioBackends,2);
ImGui::Text("Device");
ImGui::SameLine();
String audioDevName=settings.audioDevice.empty()?"<System default>":settings.audioDevice;
if (ImGui::BeginCombo("##AudioDevice",audioDevName.c_str())) {
if (ImGui::Selectable("<System default>",settings.audioDevice.empty())) {
settings.audioDevice="";
}
for (String& i: e->getAudioDevices()) {
if (ImGui::Selectable(i.c_str(),i==settings.audioDevice)) {
settings.audioDevice=i;
}
}
ImGui::EndCombo();
}
ImGui::Text("Sample rate"); ImGui::Text("Sample rate");
ImGui::SameLine(); ImGui::SameLine();
String sr=fmt::sprintf("%d",settings.audioRate); String sr=fmt::sprintf("%d",settings.audioRate);
@ -4225,6 +4240,7 @@ void FurnaceGUI::syncSettings() {
settings.patFontSize=e->getConfInt("patFontSize",18); settings.patFontSize=e->getConfInt("patFontSize",18);
settings.iconSize=e->getConfInt("iconSize",16); settings.iconSize=e->getConfInt("iconSize",16);
settings.audioEngine=(e->getConfString("audioEngine","SDL")=="SDL")?1:0; settings.audioEngine=(e->getConfString("audioEngine","SDL")=="SDL")?1:0;
settings.audioDevice=e->getConfString("audioDevice","");
settings.audioQuality=e->getConfInt("audioQuality",0); settings.audioQuality=e->getConfInt("audioQuality",0);
settings.audioBufSize=e->getConfInt("audioBufSize",1024); settings.audioBufSize=e->getConfInt("audioBufSize",1024);
settings.audioRate=e->getConfInt("audioRate",44100); settings.audioRate=e->getConfInt("audioRate",44100);
@ -4414,6 +4430,7 @@ void FurnaceGUI::commitSettings() {
e->setConf("patFontSize",settings.patFontSize); e->setConf("patFontSize",settings.patFontSize);
e->setConf("iconSize",settings.iconSize); e->setConf("iconSize",settings.iconSize);
e->setConf("audioEngine",String(audioBackends[settings.audioEngine])); e->setConf("audioEngine",String(audioBackends[settings.audioEngine]));
e->setConf("audioDevice",settings.audioDevice);
e->setConf("audioQuality",settings.audioQuality); e->setConf("audioQuality",settings.audioQuality);
e->setConf("audioBufSize",settings.audioBufSize); e->setConf("audioBufSize",settings.audioBufSize);
e->setConf("audioRate",settings.audioRate); e->setConf("audioRate",settings.audioRate);

View file

@ -408,6 +408,7 @@ class FurnaceGUI {
unsigned int maxUndoSteps; unsigned int maxUndoSteps;
String mainFontPath; String mainFontPath;
String patFontPath; String patFontPath;
String audioDevice;
Settings(): Settings():
mainFontSize(18), mainFontSize(18),
@ -443,7 +444,8 @@ class FurnaceGUI {
restartOnFlagChange(1), restartOnFlagChange(1),
maxUndoSteps(100), maxUndoSteps(100),
mainFontPath(""), mainFontPath(""),
patFontPath("") {} patFontPath(""),
audioDevice("") {}
} settings; } settings;
char finalLayoutPath[4096]; char finalLayoutPath[4096];