PC speaker: add alternative output methods
This commit is contained in:
parent
37539157be
commit
cc80bfbd81
|
|
@ -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,19 +78,76 @@ void DivPlatformPCSpeaker::pcSpeakerThread() {
|
||||||
nanosleep(&tSleep,&rSleep);
|
nanosleep(&tSleep,&rSleep);
|
||||||
}
|
}
|
||||||
if (beepFD>=0) {
|
if (beepFD>=0) {
|
||||||
ie.time.tv_sec=r.tv_sec;
|
switch (realOutMethod) {
|
||||||
ie.time.tv_usec=r.tv_nsec/1000;
|
case 0: { // evdev
|
||||||
ie.type=EV_SND;
|
static struct input_event ie;
|
||||||
ie.code=SND_TONE;
|
ie.time.tv_sec=r.tv_sec;
|
||||||
if (r.val>0) {
|
ie.time.tv_usec=r.tv_nsec/1000;
|
||||||
ie.value=chipClock/r.val;
|
ie.type=EV_SND;
|
||||||
} else {
|
ie.code=SND_TONE;
|
||||||
ie.value=0;
|
if (r.val>0) {
|
||||||
}
|
ie.value=chipClock/r.val;
|
||||||
if (write(beepFD,&ie,sizeof(struct input_event))<0) {
|
} else {
|
||||||
perror("error while writing frequency!");
|
ie.value=0;
|
||||||
} else {
|
}
|
||||||
//printf("writing freq: %d\n",r.val);
|
if (write(beepFD,&ie,sizeof(struct input_event))<0) {
|
||||||
|
perror("error while writing frequency!");
|
||||||
|
} 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 {
|
} 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) {
|
||||||
beepFD=open("/dev/input/by-path/platform-pcspkr-event-spkr",O_WRONLY);
|
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) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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(""),
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue