PC speaker: add alternative output methods

This commit is contained in:
tildearrow 2022-06-03 01:18:32 -05:00
parent 37539157be
commit cc80bfbd81
4 changed files with 129 additions and 23 deletions

View file

@ -29,6 +29,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/kd.h> #include <linux/kd.h>
#include <time.h> #include <time.h>
#include <sys/io.h>
#endif #endif
#define PCSPKR_DIVIDER 4 #define PCSPKR_DIVIDER 4
@ -59,7 +60,6 @@ void DivPlatformPCSpeaker::pcSpeakerThread() {
} }
realQueueLock.unlock(); realQueueLock.unlock();
#ifdef __linux__ #ifdef __linux__
static struct input_event ie;
static struct timespec ts, tSleep, rSleep; static struct timespec ts, tSleep, rSleep;
if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) { if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) {
printf("could not get time!\n"); printf("could not get time!\n");
@ -78,6 +78,9 @@ void DivPlatformPCSpeaker::pcSpeakerThread() {
nanosleep(&tSleep,&rSleep); nanosleep(&tSleep,&rSleep);
} }
if (beepFD>=0) { if (beepFD>=0) {
switch (realOutMethod) {
case 0: { // evdev
static struct input_event ie;
ie.time.tv_sec=r.tv_sec; ie.time.tv_sec=r.tv_sec;
ie.time.tv_usec=r.tv_nsec/1000; ie.time.tv_usec=r.tv_nsec/1000;
ie.type=EV_SND; ie.type=EV_SND;
@ -92,6 +95,60 @@ void DivPlatformPCSpeaker::pcSpeakerThread() {
} else { } else {
//printf("writing freq: %d\n",r.val); //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 { } else {
printf("not writing because fd is less than 0\n"); printf("not writing because fd is less than 0\n");
} }
@ -193,6 +250,7 @@ void DivPlatformPCSpeaker::beepFreq(int freq, int delay) {
#ifdef __linux__ #ifdef __linux__
struct timespec ts; struct timespec ts;
double addition=1000000000.0*(double)delay/(double)rate; 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) { if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) {
ts.tv_sec=0; ts.tv_sec=0;
ts.tv_nsec=0; ts.tv_nsec=0;
@ -449,19 +507,48 @@ void DivPlatformPCSpeaker::reset() {
low=0; low=0;
band=0; band=0;
if (speakerType==3) { //if (speakerType==3) {
#ifdef __linux__ #ifdef __linux__
if (beepFD==-1) { if (beepFD==-1) {
switch (realOutMethod) {
case 0: // evdev
beepFD=open("/dev/input/by-path/platform-pcspkr-event-spkr",O_WRONLY); 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) { if (beepFD<0) {
perror("error while opening PC speaker"); perror("error while opening PC speaker");
} }
} }
#endif #endif
beepFreq(0); beepFreq(0);
} else { /*} else {
beepFreq(0); beepFreq(0);
} }*/
if (realOutThread==NULL) { if (realOutThread==NULL) {
realOutThread=new std::thread(_pcSpeakerThread,this); realOutThread=new std::thread(_pcSpeakerThread,this);
@ -506,6 +593,8 @@ int DivPlatformPCSpeaker::init(DivEngine* p, int channels, int sugRate, unsigned
beepFD=-1; beepFD=-1;
realOutQuit=false; realOutQuit=false;
realOutThread=NULL; realOutThread=NULL;
realOutMethod=parent->getConfInt("pcSpeakerOutMethod",0);
realOutEnabled=false;
for (int i=0; i<1; i++) { for (int i=0; i<1; i++) {
isMuted[i]=false; isMuted[i]=false;
} }
@ -527,7 +616,7 @@ void DivPlatformPCSpeaker::quit() {
delete realOutThread; delete realOutThread;
} }
#ifdef __linux__ #ifdef __linux__
if (beepFD>=0) close(beepFD); if (beepFD>=0 && realOutMethod<3) close(beepFD);
#endif #endif
delete oscBuf; delete oscBuf;
} }

View file

@ -76,8 +76,8 @@ class DivPlatformPCSpeaker: public DivDispatch {
std::queue<RealQueueVal> realQueue; std::queue<RealQueueVal> realQueue;
std::mutex realQueueLock; std::mutex realQueueLock;
bool isMuted[1]; bool isMuted[1];
bool on, flip, lastOn; bool on, flip, lastOn, realOutEnabled;
int pos, speakerType, beepFD; int pos, speakerType, beepFD, realOutMethod;
float low, band; float low, band;
float low2, high2, band2; float low2, high2, band2;
float low3, band3; float low3, band3;

View file

@ -871,6 +871,7 @@ class FurnaceGUI {
int saaCore; int saaCore;
int nesCore; int nesCore;
int fdsCore; int fdsCore;
int pcSpeakerOutMethod;
String yrw801Path; String yrw801Path;
String tg100Path; String tg100Path;
String mu5Path; String mu5Path;
@ -905,10 +906,8 @@ class FurnaceGUI {
int avoidRaisingPattern; int avoidRaisingPattern;
int insFocusesPattern; int insFocusesPattern;
int stepOnInsert; int stepOnInsert;
// TODO flags
int unifiedDataView; int unifiedDataView;
int sysFileDialog; int sysFileDialog;
// end
int roundedWindows; int roundedWindows;
int roundedButtons; int roundedButtons;
int roundedMenus; int roundedMenus;
@ -972,6 +971,7 @@ class FurnaceGUI {
saaCore(1), saaCore(1),
nesCore(0), nesCore(0),
fdsCore(0), fdsCore(0),
pcSpeakerOutMethod(0),
yrw801Path(""), yrw801Path(""),
tg100Path(""), tg100Path(""),
mu5Path(""), mu5Path(""),

View file

@ -94,6 +94,14 @@ const char* nesCores[]={
"NSFplay" "NSFplay"
}; };
const char* pcspkrOutMethods[]={
"evdev SND_TONE",
"KIOCSOUND on /dev/tty1",
"/dev/port",
"KIOCSOUND on standard output",
"outb()"
};
const char* valueInputStyles[]={ const char* valueInputStyles[]={
"Disabled/custom", "Disabled/custom",
"Two octaves (0 is C-4, F is D#5)", "Two octaves (0 is C-4, F is D#5)",
@ -898,6 +906,12 @@ void FurnaceGUI::drawSettings() {
ImGui::SameLine(); ImGui::SameLine();
ImGui::Combo("##FDSCore",&settings.fdsCore,nesCores,2); 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::Separator();
ImGui::Text("Sample ROMs:"); ImGui::Text("Sample ROMs:");
@ -1937,6 +1951,7 @@ void FurnaceGUI::syncSettings() {
settings.saaCore=e->getConfInt("saaCore",1); settings.saaCore=e->getConfInt("saaCore",1);
settings.nesCore=e->getConfInt("nesCore",0); settings.nesCore=e->getConfInt("nesCore",0);
settings.fdsCore=e->getConfInt("fdsCore",0); settings.fdsCore=e->getConfInt("fdsCore",0);
settings.pcSpeakerOutMethod=e->getConfInt("pcSpeakerOutMethod",0);
settings.yrw801Path=e->getConfString("yrw801Path",""); settings.yrw801Path=e->getConfString("yrw801Path","");
settings.tg100Path=e->getConfString("tg100Path",""); settings.tg100Path=e->getConfString("tg100Path","");
settings.mu5Path=e->getConfString("mu5Path",""); settings.mu5Path=e->getConfString("mu5Path","");
@ -2029,6 +2044,7 @@ void FurnaceGUI::syncSettings() {
clampSetting(settings.saaCore,0,1); clampSetting(settings.saaCore,0,1);
clampSetting(settings.nesCore,0,1); clampSetting(settings.nesCore,0,1);
clampSetting(settings.fdsCore,0,1); clampSetting(settings.fdsCore,0,1);
clampSetting(settings.pcSpeakerOutMethod,0,4);
clampSetting(settings.mainFont,0,6); clampSetting(settings.mainFont,0,6);
clampSetting(settings.patFont,0,6); clampSetting(settings.patFont,0,6);
clampSetting(settings.patRowsBase,0,1); clampSetting(settings.patRowsBase,0,1);
@ -2150,6 +2166,7 @@ void FurnaceGUI::commitSettings() {
e->setConf("saaCore",settings.saaCore); e->setConf("saaCore",settings.saaCore);
e->setConf("nesCore",settings.nesCore); e->setConf("nesCore",settings.nesCore);
e->setConf("fdsCore",settings.fdsCore); e->setConf("fdsCore",settings.fdsCore);
e->setConf("pcSpeakerOutMethod",settings.pcSpeakerOutMethod);
e->setConf("yrw801Path",settings.yrw801Path); e->setConf("yrw801Path",settings.yrw801Path);
e->setConf("tg100Path",settings.tg100Path); e->setConf("tg100Path",settings.tg100Path);
e->setConf("mu5Path",settings.mu5Path); e->setConf("mu5Path",settings.mu5Path);