games/gb: better audio, scaling, fixed serious MMC5 bug

This commit is contained in:
aiju 2012-04-07 16:03:16 +02:00
parent 8ebb846fb2
commit d7f507b5b9
5 changed files with 121 additions and 27 deletions

View file

@ -6,7 +6,7 @@
#include "fns.h"
static int fd;
int ch1c, ch2c, ch3c, ch4c, ch4sr = 1;
static int sc, ch1c, ch2c, ch3c, ch4c, ch4sr = 1, ch1vec, ch2vec, ch4vec, ch1v, ch2v, ch4v;
enum { SAMPLE = 44100 };
@ -32,14 +32,75 @@ freq(int lower)
return f;
}
static void
soundlen(int len, int ctrl, int n)
{
if(mem[ctrl] & 128){
mem[0xFF26] |= (1<<n);
mem[ctrl] &= ~128;
switch(n){
case 0:
ch1v = mem[0xFF12];
break;
case 1:
ch2v = mem[0xFF17];
break;
case 3:
ch4v = mem[0xFF21];
break;
}
}
if((mem[ctrl] & 64) == 0){
mem[0xFF26] |= (1<<n);
return;
}
if((mem[0xFF26] & (1<<n)) == 0)
return;
if(mem[len] == ((n == 2) ? 255 : 63)){
mem[0xFF26] &= ~(1<<n);
return;
}
mem[len]++;
}
static void
envelope(int *v, int *c)
{
int f;
f = (*v & 7) * SAMPLE / 64;
if(f == 0)
return;
if(*c >= f){
if(*v & 8){
if((*v >> 4) < 0xF)
*v += 0x10;
}else
if((*v >> 4) > 0)
*v -= 0x10;
*c = 0;
}
(*c)++;
}
static void
dosample(short *smp)
{
int ch1s, ch2s, ch3s, ch4s, ch1f, ch2f, ch3f, ch4f, k, r, s;
u8int f;
ch4s = 0;
if(sc >= SAMPLE/256){
soundlen(0xFF11, 0xFF14, 0);
soundlen(0xFF16, 0xFF19, 1);
soundlen(0xFF1B, 0xFF1E, 2);
soundlen(0xFF20, 0xFF23, 3);
sc = 0;
}
sc++;
envelope(&ch1v, &ch1vec);
envelope(&ch2v, &ch2vec);
envelope(&ch4v, &ch4vec);
ch1f = freq(0xFF13);
if(ch1c >= ch1f)
ch1c = 0;
@ -47,8 +108,8 @@ dosample(short *smp)
ch1s = 1;
else
ch1s = -1;
ch1s *= mem[0xFF12] >> 4;
ch1s *= 10000 / 0xF;
ch1s *= ch1v >> 4;
ch1s *= 8000 / 0xF;
ch1c++;
ch2f = freq(0xFF18);
@ -58,8 +119,8 @@ dosample(short *smp)
ch2s = 1;
else
ch2s = -1;
ch2s *= mem[0xFF17] >> 4;
ch2s *= 10000 / 0xF;
ch2s *= ch2v >> 4;
ch2s *= 8000 / 0xF;
ch2c++;
ch3f = freq(0xFF1D) * 100 / 32;
@ -86,7 +147,7 @@ dosample(short *smp)
ch3s >>= 2;
break;
}
ch3s *= 10000 / 0xF;
ch3s *= 8000 / 0xF;
ch3c++;
}
@ -113,12 +174,15 @@ dosample(short *smp)
ch4s = -1;
else
ch4s = 1;
ch4s *= mem[0xFF21] >> 4;
ch4s *= 10000 / 0xF;
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;
@ -145,6 +209,10 @@ audioproc(void *)
void
initaudio(void)
{
mem[0xFF26] = 0xF;
ch1v = 0xF0;
ch2v = 0xF0;
ch4v = 0xF0;
fd = open("/dev/audio", OWRITE);
if(fd < 0)
return;

View file

@ -9,6 +9,8 @@ extern uchar mem[], *ram;
extern uchar *cart;
extern int mbc, rombanks, rambanks;
extern int scale;
enum {
rB,
rC,

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;
int mbc, rombanks, rambanks, clock, ppuclock, divclock, timerclock, syncclock, syncfreq, sleeps, checkclock, msgclock, timerfreq, timer, keys, savefd, savereq, loadreq, scale;
Rectangle picr;
Image *bg, *tmp;
Mousectl *mc;
@ -140,10 +140,10 @@ loadrom(char *file)
initdraw(nil, nil, title);
originwindow(screen, Pt(0, 0), screen->r.min);
p = divpt(addpt(screen->r.min, screen->r.max), 2);
picr = (Rectangle){subpt(p, Pt(80, 72)), addpt(p, Pt(80, 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);
if(screen->chan != XRGB32 || screen->chan != XBGR32)
tmp = allocimage(display, Rect(0, 0, 160, 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){
@ -230,10 +230,17 @@ threadmain(int argc, char** argv)
Mouse m;
Point p;
scale = 1;
ARGBEGIN{
case 'a':
initaudio();
break;
case '2':
scale = 2;
break;
case '3':
scale = 3;
break;
default:
sysfatal("unknown flag -%c", ARGC());
}ARGEND;
@ -279,7 +286,7 @@ threadmain(int argc, char** argv)
if(getwindow(display, Refnone) < 0)
sysfatal("resize failed: %r");
p = divpt(addpt(screen->r.min, screen->r.max), 2);
picr = (Rectangle){subpt(p, Pt(80, 72)), addpt(p, Pt(80, 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);
}
}

View file

@ -118,20 +118,20 @@ memwrite(u16int p, u8int v)
}
return;
case 5:
switch(p >> 13){
case 0:
switch(p >> 12){
case 0: case 1:
if((v & 0x0F) == 0x0A)
ramswitch(1, rambank);
else
ramswitch(0, rambank);
return;
case 1:
case 2:
romswitch((rombank & 0x100) | v);
return;
case 2:
case 3:
romswitch((((int)v & 1) << 8) | (rombank & 0xFF));
return;
case 3:
case 4:
ramswitch(ramen, v & 15);
return;
@ -162,6 +162,8 @@ memwrite(u16int p, u8int v)
timerfreq = 256;
}
break;
case 0xFF26:
v = (v & 0xF0) | (mem[p] & 0x0F);
case 0xFF41:
v &= ~7;
v |= mem[p] & 7;

View file

@ -5,7 +5,7 @@
#include "dat.h"
#include "fns.h"
uchar pic[160*144*4];
uchar pic[160*144*4*9];
static void
resolvetile(u8int tx, u8int ty, u8int toy, int window, u8int* tnl1, u8int *tnl2)
@ -32,17 +32,32 @@ resolvetile(u8int tx, u8int ty, u8int toy, int window, u8int* tnl1, u8int *tnl2)
static void
pixel(int x, int y, int val, int back)
{
int X, Y;
uchar *p;
val = (3 - val) * 0x55;
pic[y*160*4 + x*4] = val;
pic[y*160*4 + x*4 + 1] = val;
pic[y*160*4 + x*4 + 2] = val;
pic[y*160*4 + x*4 + 3] = back ? 0 : 0xFF;
if(scale > 1){
for(X = scale * x; X < scale * (x+1); X++)
for(Y = scale * y; Y < scale * (y+1); Y++){
p = pic + Y * scale * 160 * 4 + X * 4;
p[0] = val;
p[1] = val;
p[2] = val;
p[3] = back ? 0 : 0xFF;
}
}else{
p = pic + y*160*4 + x*4;
p[0] = val;
p[1] = val;
p[2] = val;
p[3] = back ? 0 : 0xFF;
}
}
static void
pixelbelow(int x, int y, int val)
{
if(pic[y*160*4 + x*4 + 3] == 0)
if(pic[y*scale*scale*160*4 + x*scale*4 + 3] == 0)
pixel(x, y, val, 0);
}
@ -191,10 +206,10 @@ ppustep(void)
mem[LY] = 0;
if(mem[LCDC] & LCDOP){
if(tmp){
loadimage(tmp, tmp->r, pic, sizeof(pic));
loadimage(tmp, tmp->r, pic, 160*144*4*scale*scale);
draw(screen, picr, tmp, nil, ZP);
}else
loadimage(screen, picr, pic, sizeof(pic));
loadimage(screen, picr, pic, 160*144*4*scale*scale);
flushimage(display, 1);
memset(pic, sizeof pic, 0);
}