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;
}
std::vector<String> TAAudio::listAudioDevices() {
return std::vector<String>();
}
bool TAAudio::init(TAAudioDesc& request, TAAudioDesc& response) {
response=request;
return true;

View File

@ -1,4 +1,6 @@
#include <SDL_audio.h>
#include <string.h>
#include <vector>
#include "../ta-log.h"
#include "sdl.h"
@ -49,14 +51,40 @@ bool TAAudioSDL::setRun(bool run) {
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) {
if (initialized) {
logE("audio already initialized\n");
return false;
}
if (SDL_Init(SDL_INIT_AUDIO)<0) {
logE("could not initialize SDL\n");
return false;
if (!audioSysStarted) {
if (SDL_Init(SDL_INIT_AUDIO)<0) {
logE("could not initialize SDL\n");
return false;
}
audioSysStarted=true;
}
desc=request;
@ -69,12 +97,13 @@ bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) {
ac.callback=taSDLProcess;
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) {
logE("could not open audio device: %s\n",SDL_GetError());
return false;
}
desc.deviceName=request.deviceName;
desc.name="";
desc.rate=ar.freq;
desc.inChans=0;

View File

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

View File

@ -31,7 +31,7 @@ enum TAAudioFormat {
};
struct TAAudioDesc {
String name;
String name, deviceName;
double rate;
unsigned int bufsize, fragments;
unsigned char inChans, outChans;
@ -46,40 +46,6 @@ struct TAAudioDesc {
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 {
TA_MIDI_NOTE_OFF=0x80,
@ -146,7 +112,42 @@ class TAMidiOut {
class TAMidi {
std::vector<TAMidiIn*> in;
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

View File

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

View File

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

View File

@ -3769,6 +3769,21 @@ void FurnaceGUI::drawSettings() {
ImGui::SameLine();
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::SameLine();
String sr=fmt::sprintf("%d",settings.audioRate);
@ -4225,6 +4240,7 @@ void FurnaceGUI::syncSettings() {
settings.patFontSize=e->getConfInt("patFontSize",18);
settings.iconSize=e->getConfInt("iconSize",16);
settings.audioEngine=(e->getConfString("audioEngine","SDL")=="SDL")?1:0;
settings.audioDevice=e->getConfString("audioDevice","");
settings.audioQuality=e->getConfInt("audioQuality",0);
settings.audioBufSize=e->getConfInt("audioBufSize",1024);
settings.audioRate=e->getConfInt("audioRate",44100);
@ -4414,6 +4430,7 @@ void FurnaceGUI::commitSettings() {
e->setConf("patFontSize",settings.patFontSize);
e->setConf("iconSize",settings.iconSize);
e->setConf("audioEngine",String(audioBackends[settings.audioEngine]));
e->setConf("audioDevice",settings.audioDevice);
e->setConf("audioQuality",settings.audioQuality);
e->setConf("audioBufSize",settings.audioBufSize);
e->setConf("audioRate",settings.audioRate);

View File

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