mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-05 20:35:06 +00:00
PC speaker: add alternative output methods
This commit is contained in:
parent
37539157be
commit
cc80bfbd81
4 changed files with 129 additions and 23 deletions
|
@ -29,6 +29,7 @@
|
|||
#include <linux/input.h>
|
||||
#include <linux/kd.h>
|
||||
#include <time.h>
|
||||
#include <sys/io.h>
|
||||
#endif
|
||||
|
||||
#define PCSPKR_DIVIDER 4
|
||||
|
@ -59,7 +60,6 @@ void DivPlatformPCSpeaker::pcSpeakerThread() {
|
|||
}
|
||||
realQueueLock.unlock();
|
||||
#ifdef __linux__
|
||||
static struct input_event ie;
|
||||
static struct timespec ts, tSleep, rSleep;
|
||||
if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) {
|
||||
printf("could not get time!\n");
|
||||
|
@ -78,6 +78,9 @@ void DivPlatformPCSpeaker::pcSpeakerThread() {
|
|||
nanosleep(&tSleep,&rSleep);
|
||||
}
|
||||
if (beepFD>=0) {
|
||||
switch (realOutMethod) {
|
||||
case 0: { // evdev
|
||||
static struct input_event ie;
|
||||
ie.time.tv_sec=r.tv_sec;
|
||||
ie.time.tv_usec=r.tv_nsec/1000;
|
||||
ie.type=EV_SND;
|
||||
|
@ -92,6 +95,60 @@ void DivPlatformPCSpeaker::pcSpeakerThread() {
|
|||
} else {
|
||||
//printf("writing freq: %d\n",r.val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: // KIOCSOUND (on tty)
|
||||
if (ioctl(beepFD,KIOCSOUND,r.val)<0) {
|
||||
perror("ioctl error");
|
||||
}
|
||||
break;
|
||||
case 2: { // /dev/port
|
||||
unsigned char bOut;
|
||||
bOut=0;
|
||||
if (r.val==0) {
|
||||
lseek(beepFD,0x61,SEEK_SET);
|
||||
read(beepFD,&bOut,1);
|
||||
bOut&=(~3);
|
||||
lseek(beepFD,0x61,SEEK_SET);
|
||||
write(beepFD,&bOut,1);
|
||||
} else {
|
||||
lseek(beepFD,0x43,SEEK_SET);
|
||||
bOut=0xb6;
|
||||
write(beepFD,&bOut,1);
|
||||
lseek(beepFD,0x42,SEEK_SET);
|
||||
bOut=r.val&0xff;
|
||||
write(beepFD,&bOut,1);
|
||||
lseek(beepFD,0x42,SEEK_SET);
|
||||
bOut=r.val>>8;
|
||||
write(beepFD,&bOut,1);
|
||||
lseek(beepFD,0x61,SEEK_SET);
|
||||
read(beepFD,&bOut,1);
|
||||
bOut|=3;
|
||||
lseek(beepFD,0x61,SEEK_SET);
|
||||
write(beepFD,&bOut,1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: // KIOCSOUND (on stdout)
|
||||
if (ioctl(beepFD,KIOCSOUND,r.val)<0) {
|
||||
perror("ioctl error");
|
||||
}
|
||||
break;
|
||||
case 4: // outb()
|
||||
if (r.val==0) {
|
||||
outb(inb(0x61)&(~3),0x61);
|
||||
realOutEnabled=false;
|
||||
} else {
|
||||
outb(0xb6,0x43);
|
||||
outb(r.val&0xff,0x42);
|
||||
outb(r.val>>8,0x42);
|
||||
if (!realOutEnabled) {
|
||||
outb(inb(0x61)|3,0x61);
|
||||
realOutEnabled=true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printf("not writing because fd is less than 0\n");
|
||||
}
|
||||
|
@ -193,6 +250,7 @@ void DivPlatformPCSpeaker::beepFreq(int freq, int delay) {
|
|||
#ifdef __linux__
|
||||
struct timespec ts;
|
||||
double addition=1000000000.0*(double)delay/(double)rate;
|
||||
addition+=1500000000.0*((double)parent->getAudioDescGot().bufsize/parent->getAudioDescGot().rate);
|
||||
if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) {
|
||||
ts.tv_sec=0;
|
||||
ts.tv_nsec=0;
|
||||
|
@ -449,19 +507,48 @@ void DivPlatformPCSpeaker::reset() {
|
|||
low=0;
|
||||
band=0;
|
||||
|
||||
if (speakerType==3) {
|
||||
//if (speakerType==3) {
|
||||
#ifdef __linux__
|
||||
if (beepFD==-1) {
|
||||
switch (realOutMethod) {
|
||||
case 0: // evdev
|
||||
beepFD=open("/dev/input/by-path/platform-pcspkr-event-spkr",O_WRONLY);
|
||||
break;
|
||||
case 1: // KIOCSOUND (on tty)
|
||||
beepFD=open("/dev/tty1",O_WRONLY);
|
||||
break;
|
||||
case 2: // /dev/port
|
||||
beepFD=open("/dev/port",O_WRONLY);
|
||||
break;
|
||||
case 3: // KIOCSOUND (on stdout)
|
||||
beepFD=STDOUT_FILENO;
|
||||
break;
|
||||
case 4: // outb()
|
||||
beepFD=-1;
|
||||
if (ioperm(0x61,8,1)<0) {
|
||||
perror("ioperm 0x61");
|
||||
break;
|
||||
}
|
||||
if (ioperm(0x43,8,1)<0) {
|
||||
perror("ioperm 0x43");
|
||||
break;
|
||||
}
|
||||
if (ioperm(0x42,8,1)<0) {
|
||||
perror("ioperm 0x42");
|
||||
break;
|
||||
}
|
||||
beepFD=STDOUT_FILENO;
|
||||
break;
|
||||
}
|
||||
if (beepFD<0) {
|
||||
perror("error while opening PC speaker");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
beepFreq(0);
|
||||
} else {
|
||||
/*} else {
|
||||
beepFreq(0);
|
||||
}
|
||||
}*/
|
||||
|
||||
if (realOutThread==NULL) {
|
||||
realOutThread=new std::thread(_pcSpeakerThread,this);
|
||||
|
@ -506,6 +593,8 @@ int DivPlatformPCSpeaker::init(DivEngine* p, int channels, int sugRate, unsigned
|
|||
beepFD=-1;
|
||||
realOutQuit=false;
|
||||
realOutThread=NULL;
|
||||
realOutMethod=parent->getConfInt("pcSpeakerOutMethod",0);
|
||||
realOutEnabled=false;
|
||||
for (int i=0; i<1; i++) {
|
||||
isMuted[i]=false;
|
||||
}
|
||||
|
@ -527,7 +616,7 @@ void DivPlatformPCSpeaker::quit() {
|
|||
delete realOutThread;
|
||||
}
|
||||
#ifdef __linux__
|
||||
if (beepFD>=0) close(beepFD);
|
||||
if (beepFD>=0 && realOutMethod<3) close(beepFD);
|
||||
#endif
|
||||
delete oscBuf;
|
||||
}
|
||||
|
|
|
@ -76,8 +76,8 @@ class DivPlatformPCSpeaker: public DivDispatch {
|
|||
std::queue<RealQueueVal> realQueue;
|
||||
std::mutex realQueueLock;
|
||||
bool isMuted[1];
|
||||
bool on, flip, lastOn;
|
||||
int pos, speakerType, beepFD;
|
||||
bool on, flip, lastOn, realOutEnabled;
|
||||
int pos, speakerType, beepFD, realOutMethod;
|
||||
float low, band;
|
||||
float low2, high2, band2;
|
||||
float low3, band3;
|
||||
|
|
|
@ -871,6 +871,7 @@ class FurnaceGUI {
|
|||
int saaCore;
|
||||
int nesCore;
|
||||
int fdsCore;
|
||||
int pcSpeakerOutMethod;
|
||||
String yrw801Path;
|
||||
String tg100Path;
|
||||
String mu5Path;
|
||||
|
@ -905,10 +906,8 @@ class FurnaceGUI {
|
|||
int avoidRaisingPattern;
|
||||
int insFocusesPattern;
|
||||
int stepOnInsert;
|
||||
// TODO flags
|
||||
int unifiedDataView;
|
||||
int sysFileDialog;
|
||||
// end
|
||||
int roundedWindows;
|
||||
int roundedButtons;
|
||||
int roundedMenus;
|
||||
|
@ -972,6 +971,7 @@ class FurnaceGUI {
|
|||
saaCore(1),
|
||||
nesCore(0),
|
||||
fdsCore(0),
|
||||
pcSpeakerOutMethod(0),
|
||||
yrw801Path(""),
|
||||
tg100Path(""),
|
||||
mu5Path(""),
|
||||
|
|
|
@ -94,6 +94,14 @@ const char* nesCores[]={
|
|||
"NSFplay"
|
||||
};
|
||||
|
||||
const char* pcspkrOutMethods[]={
|
||||
"evdev SND_TONE",
|
||||
"KIOCSOUND on /dev/tty1",
|
||||
"/dev/port",
|
||||
"KIOCSOUND on standard output",
|
||||
"outb()"
|
||||
};
|
||||
|
||||
const char* valueInputStyles[]={
|
||||
"Disabled/custom",
|
||||
"Two octaves (0 is C-4, F is D#5)",
|
||||
|
@ -898,6 +906,12 @@ void FurnaceGUI::drawSettings() {
|
|||
ImGui::SameLine();
|
||||
ImGui::Combo("##FDSCore",&settings.fdsCore,nesCores,2);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("PC Speaker strategy");
|
||||
ImGui::SameLine();
|
||||
ImGui::Combo("##PCSOutMethod",&settings.pcSpeakerOutMethod,pcspkrOutMethods,5);
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Sample ROMs:");
|
||||
|
||||
|
@ -1937,6 +1951,7 @@ void FurnaceGUI::syncSettings() {
|
|||
settings.saaCore=e->getConfInt("saaCore",1);
|
||||
settings.nesCore=e->getConfInt("nesCore",0);
|
||||
settings.fdsCore=e->getConfInt("fdsCore",0);
|
||||
settings.pcSpeakerOutMethod=e->getConfInt("pcSpeakerOutMethod",0);
|
||||
settings.yrw801Path=e->getConfString("yrw801Path","");
|
||||
settings.tg100Path=e->getConfString("tg100Path","");
|
||||
settings.mu5Path=e->getConfString("mu5Path","");
|
||||
|
@ -2029,6 +2044,7 @@ void FurnaceGUI::syncSettings() {
|
|||
clampSetting(settings.saaCore,0,1);
|
||||
clampSetting(settings.nesCore,0,1);
|
||||
clampSetting(settings.fdsCore,0,1);
|
||||
clampSetting(settings.pcSpeakerOutMethod,0,4);
|
||||
clampSetting(settings.mainFont,0,6);
|
||||
clampSetting(settings.patFont,0,6);
|
||||
clampSetting(settings.patRowsBase,0,1);
|
||||
|
@ -2150,6 +2166,7 @@ void FurnaceGUI::commitSettings() {
|
|||
e->setConf("saaCore",settings.saaCore);
|
||||
e->setConf("nesCore",settings.nesCore);
|
||||
e->setConf("fdsCore",settings.fdsCore);
|
||||
e->setConf("pcSpeakerOutMethod",settings.pcSpeakerOutMethod);
|
||||
e->setConf("yrw801Path",settings.yrw801Path);
|
||||
e->setConf("tg100Path",settings.tg100Path);
|
||||
e->setConf("mu5Path",settings.mu5Path);
|
||||
|
|
Loading…
Reference in a new issue