audio: add delay control

This commit is contained in:
cinap_lenrek 2011-07-03 03:42:37 +02:00
parent cd51302616
commit 86f316987d
6 changed files with 119 additions and 45 deletions

View file

@ -56,6 +56,7 @@ struct Ctlr {
int sis7012;
/* for probe */
Audio *adev;
Pcidev *pcidev;
Ctlr *next;
};
@ -286,6 +287,14 @@ outavail(void *arg)
return available(&ctlr->outring);
}
static int
outrate(void *arg)
{
Ctlr *ctlr = arg;
int delay = ctlr->adev->delay*BytesPerSample;
return (delay <= 0) || (buffered(&ctlr->outring) <= delay);
}
static long
ac97write(Audio *adev, void *vp, long n, vlong)
{
@ -312,7 +321,7 @@ ac97write(Audio *adev, void *vp, long n, vlong)
}
p += n;
}
sleep(&ring->r, outrate, ctlr);
return p - (uchar*)vp;
}
@ -383,6 +392,7 @@ ac97reset(Audio *adev)
Found:
adev->ctlr = ctlr;
ctlr->adev = adev;
if(p->vid == 0x1039 && p->did == 0x7012)
ctlr->sis7012 = 1;

View file

@ -110,6 +110,7 @@ enum {
Vrecgain,
Vmicgain,
Vspeed,
Vdelay,
};
static Volume voltab[] = {
@ -128,6 +129,7 @@ static Volume voltab[] = {
[Vrecgain] "recgain", 0x1c, 15, Stereo, 0,
[Vmicgain] "micgain", 0x1e, 15, Right, Capmic,
[Vspeed] "speed", 0x2c, 0, Absolute, 0,
[Vdelay] "delay", 0, 0, Absolute, 0,
0
};
@ -149,6 +151,10 @@ ac97volget(Audio *adev, int x, int a[2])
vol = voltab+x;
switch(vol->type){
case Absolute:
if(x == Vdelay){
a[0] = adev->delay;
break;
}
a[0] = m->rr(adev, vol->reg);
break;
default:
@ -174,7 +180,13 @@ ac97volset(Audio *adev, int x, int a[2])
vol = voltab+x;
switch(vol->type){
case Absolute:
if(x == Vdelay){
adev->delay = a[0];
return 0;
}
m->wr(adev, vol->reg, a[0]);
if(x == Vspeed)
adev->speed = m->rr(adev, vol->reg);
break;
case Left:
v = (vol->range - a[0]) & 0x7f;

View file

@ -278,6 +278,7 @@ struct Ctlr {
QLock; /* command lock */
Rendez outr;
Audio *adev;
Pcidev *pcidev;
uchar *mem;
@ -990,6 +991,14 @@ outavail(void *arg)
return ringavail(arg) > 0;
}
static int
outrate(void *arg)
{
Ctlr *ctlr = arg;
int delay = ctlr->adev->delay*4;
return (delay <= 0) || (ringused(&ctlr->ring) <= delay) || (ctlr->active == 0);
}
static int
checkptr(Ctlr *ctlr)
{
@ -1082,6 +1091,7 @@ hdawrite(Audio *adev, void *vp, long vn, vlong)
}
}
hdakick(ctlr);
sleep(&ctlr->outr, outrate, ctlr);
return vn;
}
@ -1094,26 +1104,57 @@ hdaclose(Audio *adev)
hdakick(ctlr);
}
enum {
Vmaster,
Vspeed,
Vdelay,
Nvol,
};
static Volume voltab[] = {
[0] "master", 0, 0x7f, Stereo, 0,
[Vmaster] "master", 0, 0x7f, Stereo, 0,
[Vspeed] "speed", 0, 0, Absolute, 0,
[Vdelay] "delay", 0, 0, Absolute, 0,
0
};
static int
hdagetvol(Audio *adev, int, int a[2])
hdagetvol(Audio *adev, int x, int a[2])
{
Ctlr *ctlr = adev->ctlr;
switch(x){
case Vmaster:
if(ctlr->amp != nil)
getoutamp(ctlr->amp, a);
break;
case Vspeed:
a[0] = adev->speed;
break;
case Vdelay:
a[0] = adev->delay;
break;
}
return 0;
}
static int
hdasetvol(Audio *adev, int, int a[2])
hdasetvol(Audio *adev, int x, int a[2])
{
Ctlr *ctlr = adev->ctlr;
switch(x){
case Vmaster:
if(ctlr->amp != nil)
setoutamp(ctlr->amp, 0, a);
break;
case Vspeed:
adev->speed = a[0];
break;
case Vdelay:
adev->delay = a[0];
break;
}
return 0;
}
@ -1122,13 +1163,13 @@ fillvoltab(Ctlr *ctlr, Volume *vt)
{
memmove(vt, voltab, sizeof(voltab));
if(ctlr->amp != nil)
vt[0].range = getoutamprange(ctlr->amp);
vt[Vmaster].range = getoutamprange(ctlr->amp);
}
static long
hdavolread(Audio *adev, void *a, long n, vlong)
{
Volume voltab[2];
Volume voltab[Nvol+1];
fillvoltab(adev->ctlr, voltab);
return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
}
@ -1136,7 +1177,7 @@ hdavolread(Audio *adev, void *a, long n, vlong)
static long
hdavolwrite(Audio *adev, void *a, long n, vlong)
{
Volume voltab[2];
Volume voltab[Nvol+1];
fillvoltab(adev->ctlr, voltab);
return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
}
@ -1342,6 +1383,7 @@ hdareset(Audio *adev)
Found:
adev->ctlr = ctlr;
ctlr->adev = adev;
irq = p->intl;
tbdf = p->tbdf;

View file

@ -28,6 +28,7 @@ enum
Vigain,
Vogain,
Vspeed,
Vdelay,
Nvol,
Blocksize = 4096,
@ -94,6 +95,7 @@ static Volume voltab[] = {
[Vigain] "recgain", 0x3f, 0xff, Stereo, 0,
[Vogain] "outgain", 0x41, 0xff, Stereo, 0,
[Vspeed] "speed", 0, 0, Absolute, 0,
[Vdelay] "delay", 0, 0, Absolute, 0,
0,
};
@ -239,15 +241,21 @@ mxsetvol(Audio *adev, int x, int a[2])
Ctlr *ctlr = adev->ctlr;
Volume *vol;
if(x == Vspeed){
ctlr->lvol[x] = ctlr->rvol[x] = a[0];
return 0;
}
vol = voltab+x;
blaster = &ctlr->blaster;
ilock(blaster);
switch(vol->type){
case Absolute:
switch(x){
case Vdelay:
adev->delay = a[0];
break;
case Vspeed:
adev->speed = a[0];
break;
}
ctlr->lvol[x] = ctlr->rvol[x] = a[0];
break;
case Stereo:
ctlr->rvol[x] = a[1];
mxcmd(blaster, vol->reg+1, a[1]);
@ -314,7 +322,7 @@ sb16startdma(Ctlr *ctlr)
sbcmd(blaster, 0x42); /* input sampling rate */
else
sbcmd(blaster, 0x41); /* output sampling rate */
speed = ctlr->lvol[Vspeed];
speed = ctlr->adev->speed;
sbcmd(blaster, speed>>8);
sbcmd(blaster, speed);
@ -380,7 +388,7 @@ ess1688startdma(Ctlr *ctlr)
/*
* Set the speed.
*/
speed = ctlr->lvol[Vspeed];
speed = ctlr->adev->speed;
if(speed < 4000)
speed = 4000;
else if(speed > 48000)
@ -524,6 +532,14 @@ anybuf(void *arg)
return available(&ctlr->ring) || inactive(ctlr);
}
static int
ratebuf(void *arg)
{
Ctlr *ctlr = arg;
int delay = ctlr->adev->delay*4;
return (delay <= 0) || (buffered(&ctlr->ring) <= delay) || inactive(ctlr);
}
static long
audiowrite(Audio *adev, void *vp, long n, vlong)
{
@ -546,6 +562,7 @@ audiowrite(Audio *adev, void *vp, long n, vlong)
}
p += n;
}
sleep(&ctlr->vous, ratebuf, ctlr);
return p - (uchar*)vp;
}

View file

@ -21,6 +21,9 @@ struct Audio
long (*status)(Audio *, void *, long, vlong);
long (*buffered)(Audio *);
int delay;
int speed;
int ctlrno;
Audio *next;
};

View file

@ -38,7 +38,7 @@ enum {
static Dirtab audiodir[] = {
".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
"audio", {Qaudio}, 0, 0666,
"audioctl", {Qaudioctl}, 0, 0666,
"audioctl", {Qaudioctl}, 0, 0222,
"audiostat", {Qaudiostatus}, 0, 0444,
"volume", {Qvolume}, 0, 0666,
};
@ -140,27 +140,21 @@ audioattach(char *spec)
i = 1<<adev->ctlrno;
if((attached & i) == 0 && adev->volwrite){
attached |= i;
static char *settings[] = {
"speed 44100",
"delay 882", /* 20 ms */
"master 100",
"audio 100",
"head 100",
};
strcpy(ac->buf, "speed 44100");
attached |= i;
for(i=0; i<nelem(settings); i++){
strcpy(ac->buf, settings[i]);
if(!waserror()){
adev->volwrite(adev, ac->buf, strlen(ac->buf), 0);
poperror();
}
strcpy(ac->buf, "master 100");
if(!waserror()){
adev->volwrite(adev, ac->buf, strlen(ac->buf), 0);
poperror();
}
strcpy(ac->buf, "audio 100");
if(!waserror()){
adev->volwrite(adev, ac->buf, strlen(ac->buf), 0);
poperror();
}
strcpy(ac->buf, "head 100");
if(!waserror()){
adev->volwrite(adev, ac->buf, strlen(ac->buf), 0);
poperror();
}
}
@ -202,9 +196,6 @@ audioread(Chan *c, void *a, long n, vlong off)
case Qaudio:
fn = adev->read;
break;
case Qaudioctl:
fn = adev->ctl;
break;
case Qaudiostatus:
fn = adev->status;
break;
@ -221,7 +212,6 @@ audioread(Chan *c, void *a, long n, vlong off)
nexterror();
}
switch((ulong)c->qid.path){
case Qaudioctl:
case Qaudiostatus:
case Qvolume:
/* generate the text on first read */