shithub: riscv

Download patch

ref: d7f507b5b937e7d64f337d435c395d36e990395c
parent: 8ebb846fb2b3b6ba6e828be2ba1ed37d6b4847f2
author: aiju <[email protected]>
date: Sat Apr 7 12:03:16 EDT 2012

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

--- a/sys/src/games/gb/audio.c
+++ b/sys/src/games/gb/audio.c
@@ -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 };
 
@@ -33,13 +33,74 @@
 }
 
 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 @@
 		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 @@
 		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 @@
 			ch3s >>= 2;
 			break;
 		}
-		ch3s *= 10000 / 0xF;
+		ch3s *= 8000 / 0xF;
 		ch3c++;	
 	}
 	
@@ -113,12 +174,15 @@
 		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 @@
 void
 initaudio(void)
 {
+	mem[0xFF26] = 0xF;
+	ch1v = 0xF0;
+	ch2v = 0xF0;
+	ch4v = 0xF0;
 	fd = open("/dev/audio", OWRITE);
 	if(fd < 0)
 		return;
--- a/sys/src/games/gb/dat.h
+++ b/sys/src/games/gb/dat.h
@@ -9,6 +9,8 @@
 extern uchar *cart;
 extern int mbc, rombanks, rambanks;
 
+extern int scale;
+
 enum {
 	rB,
 	rC,
--- 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;
+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 @@
 	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 @@
 	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 @@
 				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);
 			}
 		}
--- a/sys/src/games/gb/mem.c
+++ b/sys/src/games/gb/mem.c
@@ -118,20 +118,20 @@
 			}
 			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 @@
 				timerfreq = 256;
 			}
 			break;
+		case 0xFF26:
+			v = (v & 0xF0) | (mem[p] & 0x0F);
 		case 0xFF41:
 			v &= ~7;
 			v |= mem[p] & 7;
--- a/sys/src/games/gb/ppu.c
+++ b/sys/src/games/gb/ppu.c
@@ -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 @@
 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 @@
 		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);
 		}