games/gb: improve sound emulation by modelling analog behaviour
This commit is contained in:
parent
d009b0013d
commit
e8221d07d8
4 changed files with 187 additions and 146 deletions
|
@ -4,8 +4,10 @@
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
double TAU = 25000;
|
||||||
|
|
||||||
Event evsamp;
|
Event evsamp;
|
||||||
extern Event evenv, evwave;
|
extern Event evenv;
|
||||||
s16int sbuf[2*4000], *sbufp;
|
s16int sbuf[2*4000], *sbufp;
|
||||||
enum {
|
enum {
|
||||||
Freq = 44100,
|
Freq = 44100,
|
||||||
|
@ -18,29 +20,31 @@ u8int sweepen, sweepcalc, sweepctr;
|
||||||
u16int sweepfreq;
|
u16int sweepfreq;
|
||||||
typedef struct chan chan;
|
typedef struct chan chan;
|
||||||
struct chan {
|
struct chan {
|
||||||
u8int n, ectr;
|
|
||||||
u16int len;
|
|
||||||
u8int *env, *freq;
|
u8int *env, *freq;
|
||||||
u16int fctr, fthr;
|
int per;
|
||||||
u32int finc;
|
u16int len;
|
||||||
u8int vol;
|
u8int n, ectr;
|
||||||
|
u8int vol, ctr, samp;
|
||||||
};
|
};
|
||||||
u8int wpos;
|
u8int wpos;
|
||||||
u16int lfsr;
|
u16int lfsr;
|
||||||
u8int apustatus;
|
u8int apustatus;
|
||||||
ulong waveclock;
|
ulong waveclock;
|
||||||
u8int wavebuf;
|
u8int wavebuf;
|
||||||
|
double samp[2];
|
||||||
|
|
||||||
chan sndch[4] = {
|
chan sndch[4] = {
|
||||||
{
|
{
|
||||||
.n = 0,
|
.n = 0,
|
||||||
.env = reg + NR12,
|
.env = reg + NR12,
|
||||||
.freq = reg + NR14,
|
.freq = reg + NR14,
|
||||||
|
.per = 8 * 2048,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.n = 1,
|
.n = 1,
|
||||||
.env = reg + NR22,
|
.env = reg + NR22,
|
||||||
.freq = reg + NR24,
|
.freq = reg + NR24,
|
||||||
|
.per = 8 * 2048,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.n = 2,
|
.n = 2,
|
||||||
|
@ -49,114 +53,171 @@ chan sndch[4] = {
|
||||||
.n = 3,
|
.n = 3,
|
||||||
.env = reg + NR42,
|
.env = reg + NR42,
|
||||||
.freq = reg + NR44,
|
.freq = reg + NR44,
|
||||||
|
.per = 32
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Event chev[4] = {
|
||||||
|
{.aux = &sndch[0]},
|
||||||
|
{.aux = &sndch[1]},
|
||||||
|
{.aux = &sndch[2]},
|
||||||
|
{.aux = &sndch[3]}
|
||||||
|
};
|
||||||
|
|
||||||
Var apuvars[] = {
|
Var apuvars[] = {
|
||||||
VAR(apustatus), VAR(envmod), VAR(sweepen), VAR(sweepcalc),
|
VAR(apustatus), VAR(envmod), VAR(sweepen), VAR(sweepcalc),
|
||||||
VAR(sweepctr), VAR(sweepfreq), VAR(wpos), VAR(lfsr), VAR(waveclock), VAR(wavebuf),
|
VAR(sweepctr), VAR(sweepfreq), VAR(wpos), VAR(lfsr), VAR(waveclock), VAR(wavebuf),
|
||||||
VAR(sndch[0].ectr), VAR(sndch[0].len), VAR(sndch[0].fctr), VAR(sndch[0].fthr), VAR(sndch[0].finc), VAR(sndch[0].vol),
|
VAR(sndch[0].ectr), VAR(sndch[0].len), VAR(sndch[0].per), VAR(sndch[0].ctr), VAR(sndch[0].vol), VAR(sndch[0].samp),
|
||||||
VAR(sndch[1].ectr), VAR(sndch[1].len), VAR(sndch[1].fctr), VAR(sndch[1].fthr), VAR(sndch[1].finc), VAR(sndch[1].vol),
|
VAR(sndch[1].ectr), VAR(sndch[1].len), VAR(sndch[1].per), VAR(sndch[1].ctr), VAR(sndch[1].vol), VAR(sndch[1].samp),
|
||||||
VAR(sndch[2].ectr), VAR(sndch[2].len), VAR(sndch[2].fctr), VAR(sndch[2].fthr), VAR(sndch[2].finc), VAR(sndch[2].vol),
|
VAR(sndch[2].ectr), VAR(sndch[2].len), VAR(sndch[2].per), VAR(sndch[2].vol), VAR(sndch[2].samp),
|
||||||
VAR(sndch[3].ectr), VAR(sndch[3].len), VAR(sndch[3].fctr), VAR(sndch[3].fthr), VAR(sndch[3].finc), VAR(sndch[3].vol),
|
VAR(sndch[3].ectr), VAR(sndch[3].len), VAR(sndch[3].per), VAR(sndch[3].vol), VAR(sndch[3].samp),
|
||||||
{nil, 0, 0},
|
{nil, 0, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
static void
|
||||||
rate(int i, u16int v)
|
rate(chan *c, u16int v)
|
||||||
{
|
{
|
||||||
switch(i){
|
switch(c->n){
|
||||||
case 0: case 1:
|
case 0: case 1:
|
||||||
sndch[i].finc = 131072ULL * 65536 / (Freq * (2048 - (v & 0x7ff)));
|
c->per = 8 * (2048 - (v & 0x7ff));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sndch[2].finc = 4 * (2048 - (v & 0x7ff));
|
c->per = 4 * (2048 - (v & 0x7ff));
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
sndch[3].finc = 524288ULL * 65536 / Freq;
|
c->per = 32;
|
||||||
if((v & 7) != 0)
|
if((v & 7) != 0)
|
||||||
sndch[3].finc /= v & 7;
|
c->per *= v & 7;
|
||||||
else
|
else
|
||||||
sndch[3].finc <<= 1;
|
c->per >>= 1;
|
||||||
sndch[3].finc >>= (v >> 4 & 15) + 1;
|
c->per <<= (v >> 4 & 15);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
env(chan *c)
|
filter(int t)
|
||||||
{
|
{
|
||||||
if((envmod & 1) == 0 && c->len > 0 && (*c->freq & 1<<6) != 0)
|
static int ov0, ov1;
|
||||||
if(--c->len == 0){
|
static u32int oclock;
|
||||||
apustatus &= ~(1<<c->n);
|
double e;
|
||||||
c->vol = 0;
|
u8int cntl, cnth;
|
||||||
return;
|
int i, v;
|
||||||
|
|
||||||
|
e = exp((clock + t - oclock) * -(TAU / FREQ));
|
||||||
|
samp[0] = e * samp[0] + (1 - e) * ov0;
|
||||||
|
samp[1] = e * samp[1] + (1 - e) * ov1;
|
||||||
|
oclock = clock + t;
|
||||||
|
cntl = reg[NR50];
|
||||||
|
cnth = reg[NR51];
|
||||||
|
ov0 = 0;
|
||||||
|
ov1 = 0;
|
||||||
|
for(i = 0; i < 4; i++){
|
||||||
|
if(i == 2 ? ((reg[NR30] & 0x80) == 0) : ((*sndch[i].env & 0xf8) == 0))
|
||||||
|
continue;
|
||||||
|
v = sndch[i].samp * 2 - 15;
|
||||||
|
if((cnth & 1<<i) != 0)
|
||||||
|
ov0 += v;
|
||||||
|
if((cnth & 1<<4<<i) != 0)
|
||||||
|
ov1 += v;
|
||||||
|
}
|
||||||
|
ov0 *= 1 + (cntl & 7);
|
||||||
|
ov1 *= 1 + (cntl >> 4 & 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
chansamp(chan *c, int t)
|
||||||
|
{
|
||||||
|
u8int ov;
|
||||||
|
|
||||||
|
ov = c->samp;
|
||||||
|
switch(c->n){
|
||||||
|
case 0: case 1:
|
||||||
|
c->samp = c->vol;
|
||||||
|
switch(reg[NR21] >> 6){
|
||||||
|
case 0: if(c->ctr < 7) c->samp = 0; break;
|
||||||
|
case 1: if(c->ctr < 6) c->samp = 0; break;
|
||||||
|
case 2: if(c->ctr < 4) c->samp = 0; break;
|
||||||
|
case 3: if(c->ctr >= 6) c->samp = 0; break;
|
||||||
}
|
}
|
||||||
if((apustatus & 1<<c->n) == 0 || (envmod & 7) != 7 || c->ectr == 0 || --c->ectr != 0)
|
break;
|
||||||
return;
|
case 2:
|
||||||
c->ectr = *c->env & 7;
|
if((apustatus & 1<<4) == 0){
|
||||||
if((*c->env & 1<<3) != 0){
|
c->samp = 0;
|
||||||
if(c->vol < 15)
|
break;
|
||||||
c->vol++;
|
}
|
||||||
}else
|
c->samp = wavebuf;
|
||||||
if(c->vol > 0)
|
if((wpos & 1) == 0)
|
||||||
c->vol--;
|
c->samp >>= 4;
|
||||||
|
else
|
||||||
|
c->samp &= 0xf;
|
||||||
|
if((reg[NR32] & 3<<5) == 0)
|
||||||
|
c->samp = 0;
|
||||||
|
else
|
||||||
|
c->samp = c->samp >> (reg[NR32] >> 5 & 3) - 1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
c->samp = (lfsr & 1) != 0 ? 0 : c->vol;
|
||||||
|
}
|
||||||
|
if(ov != c->samp)
|
||||||
|
filter(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
wavetick(void *)
|
chantick(void *vc)
|
||||||
{
|
{
|
||||||
addevent(&evwave, sndch[2].finc);
|
chan *c;
|
||||||
wpos = wpos + 1 & 31;
|
|
||||||
wavebuf = reg[WAVE + (wpos >> 1)];
|
|
||||||
waveclock = clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
s8int
|
|
||||||
wavesamp(void)
|
|
||||||
{
|
|
||||||
u8int x;
|
|
||||||
|
|
||||||
if((apustatus & 1<<4) == 0)
|
|
||||||
return 0;
|
|
||||||
x = wavebuf;
|
|
||||||
if((wpos & 1) == 0)
|
|
||||||
x >>= 4;
|
|
||||||
else
|
|
||||||
x &= 0xf;
|
|
||||||
if((reg[NR32] & 3<<5) == 0)
|
|
||||||
x = 0;
|
|
||||||
else
|
|
||||||
x = x >> (reg[NR32] >> 5 & 3) - 1;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
s8int
|
|
||||||
lfsrsamp(void)
|
|
||||||
{
|
|
||||||
int v;
|
|
||||||
u16int l;
|
u16int l;
|
||||||
|
|
||||||
sndch[3].fctr = v = sndch[3].fctr + sndch[3].finc;
|
c = vc;
|
||||||
for(;;){
|
switch(c->n){
|
||||||
|
case 0: case 1:
|
||||||
|
c->ctr = c->ctr - 1 & 7;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
wpos = wpos + 1 & 31;
|
||||||
|
wavebuf = reg[WAVE + (wpos >> 1)];
|
||||||
|
waveclock = clock;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
l = lfsr;
|
l = lfsr;
|
||||||
v -= 0x10000;
|
|
||||||
if(v < 0)
|
|
||||||
break;
|
|
||||||
lfsr >>= 1;
|
lfsr >>= 1;
|
||||||
if(((l ^ lfsr) & 1) != 0)
|
if(((l ^ lfsr) & 1) != 0)
|
||||||
if((reg[NR43] & 1<<3) != 0)
|
if((reg[NR43] & 1<<3) != 0)
|
||||||
lfsr |= 0x40;
|
lfsr |= 0x40;
|
||||||
else
|
else
|
||||||
lfsr |= 0x4000;
|
lfsr |= 0x4000;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if((l & 1) != 0)
|
chansamp(c, chev[c->n].time);
|
||||||
return 0;
|
addevent(&chev[c->n], c->per);
|
||||||
else
|
|
||||||
return sndch[3].vol;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
sweep(int wb)
|
env(chan *c, int t)
|
||||||
|
{
|
||||||
|
if((envmod & 1) == 0 && c->len > 0 && (*c->freq & 1<<6) != 0)
|
||||||
|
if(--c->len == 0){
|
||||||
|
apustatus &= ~(1<<c->n);
|
||||||
|
c->vol = 0;
|
||||||
|
chansamp(c, t);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if((apustatus & 1<<c->n) == 0 || (envmod & 7) != 7 || c->ectr == 0 || --c->ectr != 0)
|
||||||
|
return;
|
||||||
|
c->ectr = *c->env & 7;
|
||||||
|
if((*c->env & 1<<3) != 0){
|
||||||
|
if(c->vol < 15){
|
||||||
|
c->vol++;
|
||||||
|
chansamp(c, t);
|
||||||
|
}
|
||||||
|
}else
|
||||||
|
if(c->vol > 0){
|
||||||
|
c->vol--;
|
||||||
|
chansamp(c, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sweep(int wb, int t)
|
||||||
{
|
{
|
||||||
u16int fr;
|
u16int fr;
|
||||||
int d;
|
int d;
|
||||||
|
@ -171,14 +232,15 @@ sweep(int wb)
|
||||||
if(fr > 2047){
|
if(fr > 2047){
|
||||||
sndch[0].len = 0;
|
sndch[0].len = 0;
|
||||||
sndch[0].vol = 0;
|
sndch[0].vol = 0;
|
||||||
|
chansamp(&sndch[0], t);
|
||||||
apustatus &= ~1;
|
apustatus &= ~1;
|
||||||
sweepen = 0;
|
sweepen = 0;
|
||||||
}else if(wb && (cnt & 7) != 0){
|
}else if(wb && (cnt & 7) != 0){
|
||||||
sweepfreq = fr;
|
sweepfreq = fr;
|
||||||
reg[NR13] = fr;
|
reg[NR13] = fr;
|
||||||
reg[NR14] = reg[NR14] & 0xf8 | fr >> 8;
|
reg[NR14] = reg[NR14] & 0xf8 | fr >> 8;
|
||||||
rate(0, fr);
|
rate(&sndch[0], fr);
|
||||||
sweep(0);
|
sweep(0, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +249,7 @@ sndstart(chan *c, u8int v)
|
||||||
{
|
{
|
||||||
u8int cnt;
|
u8int cnt;
|
||||||
|
|
||||||
|
filter(0);
|
||||||
c->vol = *c->env >> 4;
|
c->vol = *c->env >> 4;
|
||||||
c->ectr = *c->env & 7;
|
c->ectr = *c->env & 7;
|
||||||
if(c->len == 0)
|
if(c->len == 0)
|
||||||
|
@ -200,80 +263,46 @@ sndstart(chan *c, u8int v)
|
||||||
sweepfreq = v << 8 & 0x700 | reg[NR13];
|
sweepfreq = v << 8 & 0x700 | reg[NR13];
|
||||||
sweepcalc = 0;
|
sweepcalc = 0;
|
||||||
if((cnt & 0x07) != 0)
|
if((cnt & 0x07) != 0)
|
||||||
sweep(0);
|
sweep(0, 0);
|
||||||
}
|
}
|
||||||
if((*c->freq & 0x40) == 0 && (v & 0x40) != 0 && (envmod & 1) != 0 && --c->len == 0 || (*c->env & 0xf8) == 0){
|
if((*c->freq & 0x40) == 0 && (v & 0x40) != 0 && (envmod & 1) != 0 && --c->len == 0 || (*c->env & 0xf8) == 0){
|
||||||
apustatus &= ~(1<<c->n);
|
apustatus &= ~(1<<c->n);
|
||||||
c->vol = 0;
|
c->vol = 0;
|
||||||
}
|
}
|
||||||
|
chansamp(c, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
envtick(void *)
|
envtick(void *)
|
||||||
{
|
{
|
||||||
addevent(&evenv, FREQ / 512);
|
env(&sndch[0], evenv.time);
|
||||||
|
env(&sndch[1], evenv.time);
|
||||||
env(&sndch[0]);
|
|
||||||
env(&sndch[1]);
|
|
||||||
if((envmod & 1) == 0 && sndch[2].len > 0 && (reg[NR34] & 0x40) != 0)
|
if((envmod & 1) == 0 && sndch[2].len > 0 && (reg[NR34] & 0x40) != 0)
|
||||||
if(--sndch[2].len == 0){
|
if(--sndch[2].len == 0){
|
||||||
apustatus &= ~4;
|
apustatus &= ~4;
|
||||||
delevent(&evwave);
|
delevent(&chev[2]);
|
||||||
}
|
}
|
||||||
env(&sndch[3]);
|
env(&sndch[3], evenv.time);
|
||||||
if((envmod & 3) == 2 && sweepen && --sweepctr == 0){
|
if((envmod & 3) == 2 && sweepen && --sweepctr == 0){
|
||||||
sweepctr = reg[NR10] >> 4 & 7;
|
sweepctr = reg[NR10] >> 4 & 7;
|
||||||
sweepctr += sweepctr - 1 & 8;
|
sweepctr += sweepctr - 1 & 8;
|
||||||
if((reg[NR10] & 0x70) != 0)
|
if((reg[NR10] & 0x70) != 0)
|
||||||
sweep(1);
|
sweep(1, evenv.time);
|
||||||
}
|
}
|
||||||
envmod++;
|
envmod++;
|
||||||
|
addevent(&evenv, FREQ / 512);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sampletick(void *)
|
sampletick(void *)
|
||||||
{
|
{
|
||||||
u8int cntl, cnth;
|
filter(evsamp.time);
|
||||||
s16int ch[4];
|
|
||||||
s16int s[2];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
addevent(&evsamp, SRATEDIV);
|
|
||||||
|
|
||||||
sndch[0].fctr += sndch[0].finc;
|
|
||||||
if(sndch[0].fctr >= sndch[0].fthr)
|
|
||||||
ch[0] = sndch[0].vol;
|
|
||||||
else
|
|
||||||
ch[0] = 0;
|
|
||||||
sndch[1].fctr += sndch[1].finc;
|
|
||||||
if(sndch[1].fctr >= sndch[1].fthr)
|
|
||||||
ch[1] = sndch[1].vol;
|
|
||||||
else
|
|
||||||
ch[1] = 0;
|
|
||||||
ch[2] = wavesamp();
|
|
||||||
ch[3] = lfsrsamp();
|
|
||||||
|
|
||||||
cntl = reg[NR50];
|
|
||||||
cnth = reg[NR51];
|
|
||||||
s[0] = 0;
|
|
||||||
s[1] = 0;
|
|
||||||
for(i = 0; i < 4; i++){
|
|
||||||
if(i == 2 ? ((reg[NR30] & 0x80) == 0) : ((*sndch[i].env & 0xf8) == 0))
|
|
||||||
continue;
|
|
||||||
ch[i] = ch[i] * 2 - 15;
|
|
||||||
if((cnth & 1<<i) != 0)
|
|
||||||
s[0] += ch[i];
|
|
||||||
if((cnth & 1<<4<<i) != 0)
|
|
||||||
s[1] += ch[i];
|
|
||||||
}
|
|
||||||
s[0] *= 1 + (cntl & 7);
|
|
||||||
s[1] *= 1 + (cntl >> 4 & 7);
|
|
||||||
|
|
||||||
if(sbufp < sbuf + nelem(sbuf)){
|
if(sbufp < sbuf + nelem(sbuf)){
|
||||||
sbufp[0] = s[0] * 30;
|
sbufp[0] = samp[0] * 30;
|
||||||
sbufp[1] = s[1] * 30;
|
sbufp[1] = samp[1] * 30;
|
||||||
sbufp += 2;
|
sbufp += 2;
|
||||||
}
|
}
|
||||||
|
addevent(&evsamp, SRATEDIV);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -299,7 +328,6 @@ sndwrite(u8int a, u8int v)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NR11:
|
case NR11:
|
||||||
sndch[0].fthr = thr[v >> 6 & 3];
|
|
||||||
sndch[0].len = 64 - (v & 63);
|
sndch[0].len = 64 - (v & 63);
|
||||||
break;
|
break;
|
||||||
case NR12:
|
case NR12:
|
||||||
|
@ -309,15 +337,14 @@ sndwrite(u8int a, u8int v)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NR13:
|
case NR13:
|
||||||
rate(0, reg[NR14] << 8 & 0x700 | v);
|
rate(&sndch[0], reg[NR14] << 8 & 0x700 | v);
|
||||||
break;
|
break;
|
||||||
case NR14:
|
case NR14:
|
||||||
rate(0, v << 8 & 0x700 | reg[NR13]);
|
rate(&sndch[0], v << 8 & 0x700 | reg[NR13]);
|
||||||
if((v & 1<<7) != 0)
|
if((v & 1<<7) != 0)
|
||||||
sndstart(&sndch[0], v);
|
sndstart(&sndch[0], v);
|
||||||
break;
|
break;
|
||||||
case NR21:
|
case NR21:
|
||||||
sndch[1].fthr = thr[v >> 6 & 3];
|
|
||||||
sndch[1].len = 64 - (v & 63);
|
sndch[1].len = 64 - (v & 63);
|
||||||
break;
|
break;
|
||||||
case NR22:
|
case NR22:
|
||||||
|
@ -327,35 +354,35 @@ sndwrite(u8int a, u8int v)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NR23:
|
case NR23:
|
||||||
rate(1, reg[NR24] << 8 & 0x700 | v);
|
rate(&sndch[1], reg[NR24] << 8 & 0x700 | v);
|
||||||
break;
|
break;
|
||||||
case NR24:
|
case NR24:
|
||||||
rate(1, v << 8 & 0x700 | reg[NR23]);
|
rate(&sndch[1], v << 8 & 0x700 | reg[NR23]);
|
||||||
if((v & 1<<7) != 0)
|
if((v & 1<<7) != 0)
|
||||||
sndstart(&sndch[1], v);
|
sndstart(&sndch[1], v);
|
||||||
break;
|
break;
|
||||||
case NR30:
|
case NR30:
|
||||||
if((v & 0x80) == 0){
|
if((v & 0x80) == 0){
|
||||||
apustatus &= ~4;
|
apustatus &= ~4;
|
||||||
delevent(&evwave);
|
delevent(&chev[2]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NR31:
|
case NR31:
|
||||||
sndch[2].len = 256 - (v & 0xff);
|
sndch[2].len = 256 - (v & 0xff);
|
||||||
break;
|
break;
|
||||||
case NR33:
|
case NR33:
|
||||||
rate(2, reg[NR34] << 8 & 0x700 | v);
|
rate(&sndch[2], reg[NR34] << 8 & 0x700 | v);
|
||||||
break;
|
break;
|
||||||
case NR34:
|
case NR34:
|
||||||
rate(2, v << 8 & 0x700 | reg[NR33]);
|
rate(&sndch[2], v << 8 & 0x700 | reg[NR33]);
|
||||||
if((v & 0x80) != 0){
|
if((v & 0x80) != 0){
|
||||||
if(sndch[2].len == 0)
|
if(sndch[2].len == 0)
|
||||||
sndch[2].len = 256;
|
sndch[2].len = 256;
|
||||||
wpos = 0;
|
wpos = 0;
|
||||||
if((reg[NR30] & 0x80) != 0){
|
if((reg[NR30] & 0x80) != 0){
|
||||||
apustatus |= 4;
|
apustatus |= 4;
|
||||||
delevent(&evwave);
|
delevent(&chev[2]);
|
||||||
addevent(&evwave, sndch[2].finc);
|
addevent(&chev[2], sndch[2].per);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -369,7 +396,7 @@ sndwrite(u8int a, u8int v)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NR43:
|
case NR43:
|
||||||
rate(3, v);
|
rate(&sndch[3], v);
|
||||||
break;
|
break;
|
||||||
case NR44:
|
case NR44:
|
||||||
if((v & 1<<7) != 0){
|
if((v & 1<<7) != 0){
|
||||||
|
@ -380,6 +407,9 @@ sndwrite(u8int a, u8int v)
|
||||||
sndstart(&sndch[3], v);
|
sndstart(&sndch[3], v);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NR50: case NR51:
|
||||||
|
filter(0);
|
||||||
|
break;
|
||||||
case NR52:
|
case NR52:
|
||||||
apustatus = v & 0xf0 | apustatus & 0x0f;
|
apustatus = v & 0xf0 | apustatus & 0x0f;
|
||||||
if((v & 0x80) == 0){
|
if((v & 0x80) == 0){
|
||||||
|
@ -390,15 +420,14 @@ sndwrite(u8int a, u8int v)
|
||||||
sndch[2].len = 0;
|
sndch[2].len = 0;
|
||||||
sndch[3].len = 0;
|
sndch[3].len = 0;
|
||||||
apustatus = 0;
|
apustatus = 0;
|
||||||
delevent(&evwave);
|
delevent(&chev[2]);
|
||||||
}
|
}
|
||||||
}else if((reg[NR52] & 0x80) == 0){
|
}else if((reg[NR52] & 0x80) == 0){
|
||||||
envmod = 0;
|
envmod = 0;
|
||||||
delevent(&evenv);
|
delevent(&evenv);
|
||||||
addevent(&evenv, FREQ / 512);
|
addevent(&evenv, FREQ / 512);
|
||||||
sndch[0].fctr = 0;
|
sndch[0].ctr = 0;
|
||||||
sndch[1].fctr = 0;
|
sndch[1].ctr = 0;
|
||||||
sndch[3].fctr = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reg[a] = v;
|
reg[a] = v;
|
||||||
|
@ -430,6 +459,9 @@ audioinit(void)
|
||||||
sbufp = sbuf;
|
sbufp = sbuf;
|
||||||
evsamp.f = sampletick;
|
evsamp.f = sampletick;
|
||||||
addevent(&evsamp, SRATEDIV);
|
addevent(&evsamp, SRATEDIV);
|
||||||
|
addevent(&chev[0], 8 * 2048);
|
||||||
|
addevent(&chev[1], 8 * 2048);
|
||||||
|
addevent(&chev[3], 8 * 2048);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -155,6 +155,6 @@ struct Var {
|
||||||
};
|
};
|
||||||
#define VAR(a) {&a, sizeof(a), 1}
|
#define VAR(a) {&a, sizeof(a), 1}
|
||||||
#define ARR(a) {a, sizeof(*a), nelem(a)}
|
#define ARR(a) {a, sizeof(*a), nelem(a)}
|
||||||
enum { NEVENT = 5 };
|
enum { NEVENT = 8 };
|
||||||
extern int (*mapper)(int, int);
|
extern int (*mapper)(int, int);
|
||||||
extern u32int moncols[4];
|
extern u32int moncols[4];
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
Event evhblank, evtimer, evenv, evwave;
|
Event evhblank, evtimer, evenv;
|
||||||
extern Event evsamp;
|
extern Event evsamp, chev[4];
|
||||||
Event *events[NEVENT] = {&evhblank, &evtimer, &evenv, &evsamp, &evwave};
|
Event *events[NEVENT] = {&evhblank, &evtimer, &evenv, &evsamp, &chev[0], &chev[1], &chev[2], &chev[3]};
|
||||||
Event *elist;
|
Event *elist;
|
||||||
static int timshtab[4] = {12, 4, 6, 8}, timsh;
|
static int timshtab[4] = {12, 4, 6, 8}, timsh;
|
||||||
ulong timclock;
|
ulong timclock;
|
||||||
|
@ -109,11 +109,15 @@ eventinit(void)
|
||||||
extern void hblanktick(void *);
|
extern void hblanktick(void *);
|
||||||
extern void envtick(void *);
|
extern void envtick(void *);
|
||||||
extern void wavetick(void *);
|
extern void wavetick(void *);
|
||||||
|
extern void chantick(void *);
|
||||||
|
|
||||||
evhblank.f = hblanktick;
|
evhblank.f = hblanktick;
|
||||||
addevent(&evhblank, 240*4);
|
addevent(&evhblank, 240*4);
|
||||||
evtimer.f = timertick;
|
evtimer.f = timertick;
|
||||||
evenv.f = envtick;
|
evenv.f = envtick;
|
||||||
addevent(&evenv, FREQ / 512);
|
addevent(&evenv, FREQ / 512);
|
||||||
evwave.f = wavetick;
|
chev[0].f = chantick;
|
||||||
|
chev[1].f = chantick;
|
||||||
|
chev[2].f = chantick;
|
||||||
|
chev[3].f = chantick;
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,6 +222,7 @@ keyproc(void *)
|
||||||
static char buf[256];
|
static char buf[256];
|
||||||
char *s;
|
char *s;
|
||||||
Rune r;
|
Rune r;
|
||||||
|
extern double TAU;
|
||||||
|
|
||||||
fd = open("/dev/kbd", OREAD);
|
fd = open("/dev/kbd", OREAD);
|
||||||
if(fd < 0)
|
if(fd < 0)
|
||||||
|
@ -240,6 +241,10 @@ keyproc(void *)
|
||||||
}
|
}
|
||||||
if(utfrune(buf, 't'))
|
if(utfrune(buf, 't'))
|
||||||
trace = !trace;
|
trace = !trace;
|
||||||
|
if(utfrune(buf, KF|9))
|
||||||
|
TAU += 5000;
|
||||||
|
if(utfrune(buf, KF|10))
|
||||||
|
TAU -= 5000;
|
||||||
}
|
}
|
||||||
if(buf[0] != 'k' && buf[0] != 'K')
|
if(buf[0] != 'k' && buf[0] != 'K')
|
||||||
continue;
|
continue;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue