ref: ff5ac0c5cb11cf2770a44157107abff8536a0edc
parent: c65a3809dade0640fe6247fecb9461515857aec2
author: aiju <devnull@localhost>
date: Thu Feb 27 14:52:02 EST 2014
games/nes: improved time synchronization games/gb: added some games/nes improvements
--- a/sys/src/games/gb/audio.c
+++ b/sys/src/games/gb/audio.c
@@ -9,7 +9,7 @@
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 @@
(*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 @@
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 @@
fd = open("/dev/audio", OWRITE);
if(fd < 0)
return;
- proccreate(audioproc, nil, 8192);
+ sbufp = sbuf;
}
--- a/sys/src/games/gb/dat.h
+++ b/sys/src/games/gb/dat.h
@@ -77,4 +77,5 @@
MILLION = 1000000,
BILLION = 1000000000,
+ SAMPLE = 44100,
};
--- a/sys/src/games/gb/fns.h
+++ b/sys/src/games/gb/fns.h
@@ -8,4 +8,7 @@
void flushram(void);
void savestate(char *);
void loadstate(char *);
-void initaudio(void);
\ No newline at end of file
+void initaudio(void);
+void audiosample(void);
+int audioout(void);
+void flush(void);
--- a/sys/src/games/gb/gb.c
+++ b/sys/src/games/gb/gb.c
@@ -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 @@
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 @@
threadmain(int argc, char** argv)
{
int t;
- vlong old, new, diff;
- Mouse m;
- Point p;
scale = 1;
ARGBEGIN{
@@ -267,8 +263,6 @@
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 @@
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 @@
}
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){
@@ -338,5 +309,45 @@
msgclock = 0;
}
}
+ }
+}
+
+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();
}
}
--- a/sys/src/games/gb/ppu.c
+++ b/sys/src/games/gb/ppu.c
@@ -177,9 +177,6 @@
void
ppustep(void)
{
- extern Rectangle picr;
- extern Image *tmp;
-
if(mem[LY] == 144){
mem[STAT] &= ~3;
mem[STAT] |= 1;
@@ -204,14 +201,8 @@
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();
}
}
--- a/sys/src/games/nes/ppu.c
+++ b/sys/src/games/nes/ppu.c
@@ -255,8 +255,8 @@
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 @@
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;
+ }
}
}