games/nes: improved time synchronization
games/gb: added some games/nes improvements
This commit is contained in:
parent
c65a3809da
commit
ff5ac0c5cb
|
@ -9,7 +9,7 @@ static int fd;
|
||||||
static int sc, ch1c, ch2c, ch3c, ch4c, ch4sr = 1, ch1vec, ch2vec, ch4vec, ch1v, ch2v, ch4v;
|
static int sc, ch1c, ch2c, ch3c, ch4c, ch4sr = 1, ch1vec, ch2vec, ch4vec, ch1v, ch2v, ch4v;
|
||||||
extern int paused;
|
extern int paused;
|
||||||
|
|
||||||
enum { SAMPLE = 44100 };
|
static short sbuf[2*2000], *sbufp;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
thresh(int f, int b)
|
thresh(int f, int b)
|
||||||
|
@ -84,12 +84,14 @@ envelope(int *v, int *c)
|
||||||
(*c)++;
|
(*c)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
dosample(short *smp)
|
audiosample(void)
|
||||||
{
|
{
|
||||||
int ch1s, ch2s, ch3s, ch4s, ch1f, ch2f, ch3f, ch4f, k, r, s;
|
int ch1s, ch2s, ch3s, ch4s, ch1f, ch2f, ch3f, ch4f, k, r, s;
|
||||||
u8int f;
|
u8int f;
|
||||||
|
|
||||||
|
if(sbufp == nil)
|
||||||
|
return;
|
||||||
if(sc >= SAMPLE/256){
|
if(sc >= SAMPLE/256){
|
||||||
soundlen(0xFF11, 0xFF14, 0);
|
soundlen(0xFF11, 0xFF14, 0);
|
||||||
soundlen(0xFF16, 0xFF19, 1);
|
soundlen(0xFF16, 0xFF19, 1);
|
||||||
|
@ -179,51 +181,40 @@ dosample(short *smp)
|
||||||
ch4s *= ch4v >> 4;
|
ch4s *= ch4v >> 4;
|
||||||
ch4s *= 8000 / 0xF;
|
ch4s *= 8000 / 0xF;
|
||||||
|
|
||||||
smp[0] = 0;
|
|
||||||
smp[1] = 0;
|
|
||||||
f = mem[0xFF25];
|
f = mem[0xFF25];
|
||||||
r = mem[0xFF26] & 15;
|
r = mem[0xFF26] & 15;
|
||||||
r = r | (r << 4);
|
r = r | (r << 4);
|
||||||
f &= r;
|
f &= r;
|
||||||
if(f & 0x01) smp[0] += ch1s;
|
if(sbufp < sbuf + nelem(sbuf) - 1){
|
||||||
if(f & 0x02) smp[0] += ch2s;
|
*sbufp = 0;
|
||||||
if(f & 0x04) smp[0] += ch3s;
|
if(f & 0x01) *sbufp += ch1s;
|
||||||
if(f & 0x08) smp[0] += ch4s;
|
if(f & 0x02) *sbufp += ch2s;
|
||||||
if(f & 0x10) smp[1] += ch1s;
|
if(f & 0x04) *sbufp += ch3s;
|
||||||
if(f & 0x20) smp[1] += ch2s;
|
if(f & 0x08) *sbufp += ch4s;
|
||||||
if(f & 0x40) smp[1] += ch3s;
|
*++sbufp = 0;
|
||||||
if(f & 0x80) smp[1] += ch4s;
|
if(f & 0x10) *sbufp += ch1s;
|
||||||
}
|
if(f & 0x20) *sbufp += ch2s;
|
||||||
|
if(f & 0x40) *sbufp += ch3s;
|
||||||
void
|
if(f & 0x80) *sbufp += ch4s;
|
||||||
setpri(int pri)
|
sbufp++;
|
||||||
{
|
|
||||||
char buf[64];
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid());
|
|
||||||
if((fd = open(buf, OWRITE)) >= 0){
|
|
||||||
fprint(fd, "pri %d\n", pri);
|
|
||||||
close(fd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
audioproc(void *)
|
audioout(void)
|
||||||
{
|
{
|
||||||
short samples[10 * 2];
|
int rc;
|
||||||
int i;
|
|
||||||
|
|
||||||
setpri(13);
|
if(sbufp == nil)
|
||||||
|
return -1;
|
||||||
for(;;){
|
if(sbufp == sbuf)
|
||||||
if(paused)
|
return 0;
|
||||||
memset(samples, 0, sizeof samples);
|
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
|
||||||
else
|
if(rc > 0)
|
||||||
for(i = 0; i < sizeof samples/4; i++)
|
sbufp -= (rc+1)/2;
|
||||||
dosample(samples + 2 * i);
|
if(sbufp < sbuf)
|
||||||
write(fd, samples, sizeof samples);
|
sbufp = sbuf;
|
||||||
}
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -236,5 +227,5 @@ initaudio(void)
|
||||||
fd = open("/dev/audio", OWRITE);
|
fd = open("/dev/audio", OWRITE);
|
||||||
if(fd < 0)
|
if(fd < 0)
|
||||||
return;
|
return;
|
||||||
proccreate(audioproc, nil, 8192);
|
sbufp = sbuf;
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,4 +77,5 @@ enum {
|
||||||
|
|
||||||
MILLION = 1000000,
|
MILLION = 1000000,
|
||||||
BILLION = 1000000000,
|
BILLION = 1000000000,
|
||||||
|
SAMPLE = 44100,
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,3 +9,6 @@ void flushram(void);
|
||||||
void savestate(char *);
|
void savestate(char *);
|
||||||
void loadstate(char *);
|
void loadstate(char *);
|
||||||
void initaudio(void);
|
void initaudio(void);
|
||||||
|
void audiosample(void);
|
||||||
|
int audioout(void);
|
||||||
|
void flush(void);
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
uchar *cart, *ram;
|
uchar *cart, *ram;
|
||||||
int mbc, rombanks, rambanks, clock, ppuclock, divclock, timerclock, syncclock, syncfreq, sleeps, checkclock, msgclock, timerfreq, timer, keys, savefd, savereq, loadreq, scale, paused;
|
int mbc, rombanks, rambanks, clock, ppuclock, divclock, timerclock, audioclock, msgclock, timerfreq, timer, keys, savefd, savereq, loadreq, scale, paused;
|
||||||
Rectangle picr;
|
Rectangle picr;
|
||||||
Image *bg, *tmp;
|
Image *bg, *tmp;
|
||||||
Mousectl *mc;
|
Mousectl *mc;
|
||||||
|
@ -143,8 +143,7 @@ loadrom(char *file)
|
||||||
p = divpt(addpt(screen->r.min, screen->r.max), 2);
|
p = divpt(addpt(screen->r.min, screen->r.max), 2);
|
||||||
picr = (Rectangle){subpt(p, Pt(scale * 80, scale * 72)), addpt(p, Pt(scale * 80, scale * 72))};
|
picr = (Rectangle){subpt(p, Pt(scale * 80, scale * 72)), addpt(p, Pt(scale * 80, scale * 72))};
|
||||||
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
||||||
if(screen->chan != XRGB32 || screen->chan != XBGR32)
|
tmp = allocimage(display, Rect(0, 0, scale * 160, scale * 144), XRGB32, 0, 0);
|
||||||
tmp = allocimage(display, Rect(0, 0, scale * 160, scale * 144), XRGB32, 0, 0);
|
|
||||||
draw(screen, screen->r, bg, nil, ZP);
|
draw(screen, screen->r, bg, nil, ZP);
|
||||||
|
|
||||||
if(ram && battery){
|
if(ram && battery){
|
||||||
|
@ -234,9 +233,6 @@ void
|
||||||
threadmain(int argc, char** argv)
|
threadmain(int argc, char** argv)
|
||||||
{
|
{
|
||||||
int t;
|
int t;
|
||||||
vlong old, new, diff;
|
|
||||||
Mouse m;
|
|
||||||
Point p;
|
|
||||||
|
|
||||||
scale = 1;
|
scale = 1;
|
||||||
ARGBEGIN{
|
ARGBEGIN{
|
||||||
|
@ -267,8 +263,6 @@ threadmain(int argc, char** argv)
|
||||||
if(mc == nil)
|
if(mc == nil)
|
||||||
sysfatal("init mouse: %r");
|
sysfatal("init mouse: %r");
|
||||||
proccreate(keyproc, nil, 8192);
|
proccreate(keyproc, nil, 8192);
|
||||||
syncfreq = CPUFREQ / 50;
|
|
||||||
old = nsec();
|
|
||||||
for(;;){
|
for(;;){
|
||||||
if(savereq){
|
if(savereq){
|
||||||
savestate("gb.save");
|
savestate("gb.save");
|
||||||
|
@ -286,26 +280,20 @@ threadmain(int argc, char** argv)
|
||||||
clock += t;
|
clock += t;
|
||||||
ppuclock += t;
|
ppuclock += t;
|
||||||
divclock += t;
|
divclock += t;
|
||||||
|
audioclock += t;
|
||||||
timerclock += t;
|
timerclock += t;
|
||||||
syncclock += t;
|
|
||||||
checkclock += t;
|
|
||||||
if(ppuclock >= 456){
|
if(ppuclock >= 456){
|
||||||
ppustep();
|
ppustep();
|
||||||
ppuclock -= 456;
|
ppuclock -= 456;
|
||||||
while(nbrecv(mc->c, &m) > 0)
|
|
||||||
;
|
|
||||||
if(nbrecvul(mc->resizec) > 0){
|
|
||||||
if(getwindow(display, Refnone) < 0)
|
|
||||||
sysfatal("resize failed: %r");
|
|
||||||
p = divpt(addpt(screen->r.min, screen->r.max), 2);
|
|
||||||
picr = (Rectangle){subpt(p, Pt(scale * 80, scale * 72)), addpt(p, Pt(scale * 80, scale * 72))};
|
|
||||||
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(divclock >= 256){
|
if(divclock >= 256){
|
||||||
mem[DIV]++;
|
mem[DIV]++;
|
||||||
divclock = 0;
|
divclock = 0;
|
||||||
}
|
}
|
||||||
|
if(audioclock >= CPUFREQ / SAMPLE){
|
||||||
|
audiosample();
|
||||||
|
audioclock -= CPUFREQ / SAMPLE;
|
||||||
|
}
|
||||||
if(timer && timerclock >= timerfreq){
|
if(timer && timerclock >= timerfreq){
|
||||||
mem[TIMA]++;
|
mem[TIMA]++;
|
||||||
if(mem[TIMA] == 0){
|
if(mem[TIMA] == 0){
|
||||||
|
@ -314,23 +302,6 @@ threadmain(int argc, char** argv)
|
||||||
}
|
}
|
||||||
timerclock = 0;
|
timerclock = 0;
|
||||||
}
|
}
|
||||||
if(syncclock >= syncfreq){
|
|
||||||
sleep(10);
|
|
||||||
sleeps++;
|
|
||||||
syncclock = 0;
|
|
||||||
}
|
|
||||||
if(checkclock >= CPUFREQ){
|
|
||||||
new = nsec();
|
|
||||||
diff = new - old - sleeps * 10 * MILLION;
|
|
||||||
diff = BILLION - diff;
|
|
||||||
if(diff <= 0)
|
|
||||||
syncfreq = CPUFREQ;
|
|
||||||
else
|
|
||||||
syncfreq = ((vlong)CPUFREQ) * 10 * MILLION / diff;
|
|
||||||
old = new;
|
|
||||||
checkclock = 0;
|
|
||||||
sleeps = 0;
|
|
||||||
}
|
|
||||||
if(msgclock > 0){
|
if(msgclock > 0){
|
||||||
msgclock -= t;
|
msgclock -= t;
|
||||||
if(msgclock <= 0){
|
if(msgclock <= 0){
|
||||||
|
@ -340,3 +311,43 @@ threadmain(int argc, char** argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
flush(void)
|
||||||
|
{
|
||||||
|
extern uchar pic[160*144*4*3*3];
|
||||||
|
Mouse m;
|
||||||
|
Point p;
|
||||||
|
static vlong old;
|
||||||
|
vlong new, diff;
|
||||||
|
|
||||||
|
while(nbrecv(mc->c, &m) > 0)
|
||||||
|
;
|
||||||
|
if(nbrecvul(mc->resizec) > 0){
|
||||||
|
if(getwindow(display, Refnone) < 0)
|
||||||
|
sysfatal("resize failed: %r");
|
||||||
|
p = divpt(addpt(screen->r.min, screen->r.max), 2);
|
||||||
|
picr = (Rectangle){subpt(p, Pt(scale * 80, scale * 72)), addpt(p, Pt(scale * 80, scale * 72))};
|
||||||
|
if(bg->chan != screen->chan){
|
||||||
|
freeimage(bg);
|
||||||
|
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
||||||
|
}
|
||||||
|
draw(screen, screen->r, bg, nil, ZP);
|
||||||
|
}
|
||||||
|
if(screen->chan != tmp->chan){
|
||||||
|
loadimage(tmp, tmp->r, pic, 160*144*4*scale*scale);
|
||||||
|
draw(screen, picr, tmp, nil, ZP);
|
||||||
|
}else
|
||||||
|
loadimage(screen, picr, pic, 160*144*4*scale*scale);
|
||||||
|
flushimage(display, 1);
|
||||||
|
memset(pic, sizeof pic, 0);
|
||||||
|
if(audioout() < 0){
|
||||||
|
new = nsec();
|
||||||
|
if(old != 0){
|
||||||
|
diff = BILLION/60 - (new - old);
|
||||||
|
if(diff >= MILLION)
|
||||||
|
sleep(diff/MILLION);
|
||||||
|
}
|
||||||
|
old = nsec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -177,9 +177,6 @@ drawwindow(void)
|
||||||
void
|
void
|
||||||
ppustep(void)
|
ppustep(void)
|
||||||
{
|
{
|
||||||
extern Rectangle picr;
|
|
||||||
extern Image *tmp;
|
|
||||||
|
|
||||||
if(mem[LY] == 144){
|
if(mem[LY] == 144){
|
||||||
mem[STAT] &= ~3;
|
mem[STAT] &= ~3;
|
||||||
mem[STAT] |= 1;
|
mem[STAT] |= 1;
|
||||||
|
@ -204,14 +201,8 @@ ppustep(void)
|
||||||
mem[LY]++;
|
mem[LY]++;
|
||||||
if(mem[LY] > 160){
|
if(mem[LY] > 160){
|
||||||
mem[LY] = 0;
|
mem[LY] = 0;
|
||||||
if(mem[LCDC] & LCDOP){
|
if((mem[LCDC] & LCDOP) == 0)
|
||||||
if(tmp){
|
memset(pic, 0, sizeof(pic));
|
||||||
loadimage(tmp, tmp->r, pic, 160*144*4*scale*scale);
|
flush();
|
||||||
draw(screen, picr, tmp, nil, ZP);
|
|
||||||
}else
|
|
||||||
loadimage(screen, picr, pic, 160*144*4*scale*scale);
|
|
||||||
flushimage(display, 1);
|
|
||||||
memset(pic, sizeof pic, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -255,8 +255,8 @@ flush(void)
|
||||||
extern Rectangle picr;
|
extern Rectangle picr;
|
||||||
extern Image *tmp, *bg;
|
extern Image *tmp, *bg;
|
||||||
extern Mousectl *mc;
|
extern Mousectl *mc;
|
||||||
static vlong old, diff;
|
static vlong old, delta;
|
||||||
vlong new;
|
vlong new, diff;
|
||||||
Mouse m;
|
Mouse m;
|
||||||
Point p;
|
Point p;
|
||||||
int h;
|
int h;
|
||||||
|
@ -286,12 +286,17 @@ flush(void)
|
||||||
memset(pic, sizeof pic, 0);
|
memset(pic, sizeof pic, 0);
|
||||||
if(audioout() < 0){
|
if(audioout() < 0){
|
||||||
new = nsec();
|
new = nsec();
|
||||||
|
diff = 0;
|
||||||
if(old != 0){
|
if(old != 0){
|
||||||
diff = BILLION/60 - (new - old);
|
diff = BILLION/60 - (new - old) - delta;
|
||||||
if(diff >= MILLION)
|
if(diff >= MILLION)
|
||||||
sleep(diff/MILLION);
|
sleep(diff/MILLION);
|
||||||
}
|
}
|
||||||
old = new;
|
old = nsec();
|
||||||
|
if(diff != 0){
|
||||||
|
diff = (old - new) - (diff / MILLION) * MILLION;
|
||||||
|
delta += (diff - delta) / 100;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue