mirror of
https://github.com/tildearrow/furnace.git
synced 2025-01-05 23:21:22 +00:00
add an option to select audio device
This commit is contained in:
parent
d2d60c4f1a
commit
53482105dc
8 changed files with 119 additions and 40 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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];
|
||||||
|
|
Loading…
Reference in a new issue