games/nes: improved time synchronization

games/gb: added some games/nes improvements
front
aiju 2014-02-27 19:52:02 +01:00
parent c65a3809da
commit ff5ac0c5cb
6 changed files with 95 additions and 93 deletions

View File

@ -9,7 +9,7 @@ static int fd;
static int sc, ch1c, ch2c, ch3c, ch4c, ch4sr = 1, ch1vec, ch2vec, ch4vec, ch1v, ch2v, ch4v;
extern int paused;
enum { SAMPLE = 44100 };
static short sbuf[2*2000], *sbufp;
static int
thresh(int f, int b)
@ -84,12 +84,14 @@ envelope(int *v, int *c)
(*c)++;
}
static void
dosample(short *smp)
void
audiosample(void)
{
int ch1s, ch2s, ch3s, ch4s, ch1f, ch2f, ch3f, ch4f, k, r, s;
u8int f;
if(sbufp == nil)
return;
if(sc >= SAMPLE/256){
soundlen(0xFF11, 0xFF14, 0);
soundlen(0xFF16, 0xFF19, 1);
@ -179,51 +181,40 @@ dosample(short *smp)
ch4s *= ch4v >> 4;
ch4s *= 8000 / 0xF;
smp[0] = 0;
smp[1] = 0;
f = mem[0xFF25];
r = mem[0xFF26] & 15;
r = r | (r << 4);
f &= r;
if(f & 0x01) smp[0] += ch1s;
if(f & 0x02) smp[0] += ch2s;
if(f & 0x04) smp[0] += ch3s;
if(f & 0x08) smp[0] += ch4s;
if(f & 0x10) smp[1] += ch1s;
if(f & 0x20) smp[1] += ch2s;
if(f & 0x40) smp[1] += ch3s;
if(f & 0x80) smp[1] += ch4s;
}
void
setpri(int pri)
{
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);
if(sbufp < sbuf + nelem(sbuf) - 1){
*sbufp = 0;
if(f & 0x01) *sbufp += ch1s;
if(f & 0x02) *sbufp += ch2s;
if(f & 0x04) *sbufp += ch3s;
if(f & 0x08) *sbufp += ch4s;
*++sbufp = 0;
if(f & 0x10) *sbufp += ch1s;
if(f & 0x20) *sbufp += ch2s;
if(f & 0x40) *sbufp += ch3s;
if(f & 0x80) *sbufp += ch4s;
sbufp++;
}
}
void
audioproc(void *)
int
audioout(void)
{
short samples[10 * 2];
int i;
int rc;
setpri(13);
for(;;){
if(paused)
memset(samples, 0, sizeof samples);
else
for(i = 0; i < sizeof samples/4; i++)
dosample(samples + 2 * i);
write(fd, samples, sizeof samples);
}
if(sbufp == nil)
return -1;
if(sbufp == sbuf)
return 0;
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
if(rc > 0)
sbufp -= (rc+1)/2;
if(sbufp < sbuf)
sbufp = sbuf;
return 0;
}
void
@ -236,5 +227,5 @@ initaudio(void)
fd = open("/dev/audio", OWRITE);
if(fd < 0)
return;
proccreate(audioproc, nil, 8192);
sbufp = sbuf;
}

View File

@ -77,4 +77,5 @@ enum {
MILLION = 1000000,
BILLION = 1000000000,
SAMPLE = 44100,
};

View File

@ -8,4 +8,7 @@ void message(char *, ...);
void flushram(void);
void savestate(char *);
void loadstate(char *);
void initaudio(void);
void initaudio(void);
void audiosample(void);
int audioout(void);
void flush(void);

View File

@ -9,7 +9,7 @@
#include "fns.h"
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;
Image *bg, *tmp;
Mousectl *mc;
@ -143,8 +143,7 @@ loadrom(char *file)
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(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);
if(ram && battery){
@ -234,9 +233,6 @@ void
threadmain(int argc, char** argv)
{
int t;
vlong old, new, diff;
Mouse m;
Point p;
scale = 1;
ARGBEGIN{
@ -267,8 +263,6 @@ threadmain(int argc, char** argv)
if(mc == nil)
sysfatal("init mouse: %r");
proccreate(keyproc, nil, 8192);
syncfreq = CPUFREQ / 50;
old = nsec();
for(;;){
if(savereq){
savestate("gb.save");
@ -286,26 +280,20 @@ threadmain(int argc, char** argv)
clock += t;
ppuclock += t;
divclock += t;
audioclock += t;
timerclock += t;
syncclock += t;
checkclock += t;
if(ppuclock >= 456){
ppustep();
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){
mem[DIV]++;
divclock = 0;
}
if(audioclock >= CPUFREQ / SAMPLE){
audiosample();
audioclock -= CPUFREQ / SAMPLE;
}
if(timer && timerclock >= timerfreq){
mem[TIMA]++;
if(mem[TIMA] == 0){
@ -314,23 +302,6 @@ threadmain(int argc, char** argv)
}
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){
msgclock -= t;
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();
}
}

View File

@ -177,9 +177,6 @@ drawwindow(void)
void
ppustep(void)
{
extern Rectangle picr;
extern Image *tmp;
if(mem[LY] == 144){
mem[STAT] &= ~3;
mem[STAT] |= 1;
@ -204,14 +201,8 @@ ppustep(void)
mem[LY]++;
if(mem[LY] > 160){
mem[LY] = 0;
if(mem[LCDC] & LCDOP){
if(tmp){
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((mem[LCDC] & LCDOP) == 0)
memset(pic, 0, sizeof(pic));
flush();
}
}

View File

@ -255,8 +255,8 @@ flush(void)
extern Rectangle picr;
extern Image *tmp, *bg;
extern Mousectl *mc;
static vlong old, diff;
vlong new;
static vlong old, delta;
vlong new, diff;
Mouse m;
Point p;
int h;
@ -286,12 +286,17 @@ flush(void)
memset(pic, sizeof pic, 0);
if(audioout() < 0){
new = nsec();
diff = 0;
if(old != 0){
diff = BILLION/60 - (new - old);
diff = BILLION/60 - (new - old) - delta;
if(diff >= MILLION)
sleep(diff/MILLION);
}
old = new;
old = nsec();
if(diff != 0){
diff = (old - new) - (diff / MILLION) * MILLION;
delta += (diff - delta) / 100;
}
}
}