audio: add delay control
This commit is contained in:
parent
cd51302616
commit
86f316987d
6 changed files with 119 additions and 45 deletions
|
@ -56,6 +56,7 @@ struct Ctlr {
|
||||||
int sis7012;
|
int sis7012;
|
||||||
|
|
||||||
/* for probe */
|
/* for probe */
|
||||||
|
Audio *adev;
|
||||||
Pcidev *pcidev;
|
Pcidev *pcidev;
|
||||||
Ctlr *next;
|
Ctlr *next;
|
||||||
};
|
};
|
||||||
|
@ -286,6 +287,14 @@ outavail(void *arg)
|
||||||
return available(&ctlr->outring);
|
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
|
static long
|
||||||
ac97write(Audio *adev, void *vp, long n, vlong)
|
ac97write(Audio *adev, void *vp, long n, vlong)
|
||||||
{
|
{
|
||||||
|
@ -312,7 +321,7 @@ ac97write(Audio *adev, void *vp, long n, vlong)
|
||||||
}
|
}
|
||||||
p += n;
|
p += n;
|
||||||
}
|
}
|
||||||
|
sleep(&ring->r, outrate, ctlr);
|
||||||
return p - (uchar*)vp;
|
return p - (uchar*)vp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,6 +392,7 @@ ac97reset(Audio *adev)
|
||||||
|
|
||||||
Found:
|
Found:
|
||||||
adev->ctlr = ctlr;
|
adev->ctlr = ctlr;
|
||||||
|
ctlr->adev = adev;
|
||||||
if(p->vid == 0x1039 && p->did == 0x7012)
|
if(p->vid == 0x1039 && p->did == 0x7012)
|
||||||
ctlr->sis7012 = 1;
|
ctlr->sis7012 = 1;
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,7 @@ enum {
|
||||||
Vrecgain,
|
Vrecgain,
|
||||||
Vmicgain,
|
Vmicgain,
|
||||||
Vspeed,
|
Vspeed,
|
||||||
|
Vdelay,
|
||||||
};
|
};
|
||||||
|
|
||||||
static Volume voltab[] = {
|
static Volume voltab[] = {
|
||||||
|
@ -128,6 +129,7 @@ static Volume voltab[] = {
|
||||||
[Vrecgain] "recgain", 0x1c, 15, Stereo, 0,
|
[Vrecgain] "recgain", 0x1c, 15, Stereo, 0,
|
||||||
[Vmicgain] "micgain", 0x1e, 15, Right, Capmic,
|
[Vmicgain] "micgain", 0x1e, 15, Right, Capmic,
|
||||||
[Vspeed] "speed", 0x2c, 0, Absolute, 0,
|
[Vspeed] "speed", 0x2c, 0, Absolute, 0,
|
||||||
|
[Vdelay] "delay", 0, 0, Absolute, 0,
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -149,6 +151,10 @@ ac97volget(Audio *adev, int x, int a[2])
|
||||||
vol = voltab+x;
|
vol = voltab+x;
|
||||||
switch(vol->type){
|
switch(vol->type){
|
||||||
case Absolute:
|
case Absolute:
|
||||||
|
if(x == Vdelay){
|
||||||
|
a[0] = adev->delay;
|
||||||
|
break;
|
||||||
|
}
|
||||||
a[0] = m->rr(adev, vol->reg);
|
a[0] = m->rr(adev, vol->reg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -174,7 +180,13 @@ ac97volset(Audio *adev, int x, int a[2])
|
||||||
vol = voltab+x;
|
vol = voltab+x;
|
||||||
switch(vol->type){
|
switch(vol->type){
|
||||||
case Absolute:
|
case Absolute:
|
||||||
m->wr(adev, vol->reg, a[0]);
|
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;
|
break;
|
||||||
case Left:
|
case Left:
|
||||||
v = (vol->range - a[0]) & 0x7f;
|
v = (vol->range - a[0]) & 0x7f;
|
||||||
|
|
|
@ -277,7 +277,8 @@ struct Ctlr {
|
||||||
Lock; /* interrupt lock */
|
Lock; /* interrupt lock */
|
||||||
QLock; /* command lock */
|
QLock; /* command lock */
|
||||||
Rendez outr;
|
Rendez outr;
|
||||||
|
|
||||||
|
Audio *adev;
|
||||||
Pcidev *pcidev;
|
Pcidev *pcidev;
|
||||||
|
|
||||||
uchar *mem;
|
uchar *mem;
|
||||||
|
@ -990,6 +991,14 @@ outavail(void *arg)
|
||||||
return ringavail(arg) > 0;
|
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
|
static int
|
||||||
checkptr(Ctlr *ctlr)
|
checkptr(Ctlr *ctlr)
|
||||||
{
|
{
|
||||||
|
@ -1082,6 +1091,7 @@ hdawrite(Audio *adev, void *vp, long vn, vlong)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hdakick(ctlr);
|
hdakick(ctlr);
|
||||||
|
sleep(&ctlr->outr, outrate, ctlr);
|
||||||
return vn;
|
return vn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1094,26 +1104,57 @@ hdaclose(Audio *adev)
|
||||||
hdakick(ctlr);
|
hdakick(ctlr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Vmaster,
|
||||||
|
Vspeed,
|
||||||
|
Vdelay,
|
||||||
|
Nvol,
|
||||||
|
};
|
||||||
|
|
||||||
static Volume voltab[] = {
|
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
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
hdagetvol(Audio *adev, int, int a[2])
|
hdagetvol(Audio *adev, int x, int a[2])
|
||||||
{
|
{
|
||||||
Ctlr *ctlr = adev->ctlr;
|
Ctlr *ctlr = adev->ctlr;
|
||||||
if(ctlr->amp != nil)
|
|
||||||
getoutamp(ctlr->amp, a);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
hdasetvol(Audio *adev, int, int a[2])
|
hdasetvol(Audio *adev, int x, int a[2])
|
||||||
{
|
{
|
||||||
Ctlr *ctlr = adev->ctlr;
|
Ctlr *ctlr = adev->ctlr;
|
||||||
if(ctlr->amp != nil)
|
|
||||||
setoutamp(ctlr->amp, 0, a);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1122,13 +1163,13 @@ fillvoltab(Ctlr *ctlr, Volume *vt)
|
||||||
{
|
{
|
||||||
memmove(vt, voltab, sizeof(voltab));
|
memmove(vt, voltab, sizeof(voltab));
|
||||||
if(ctlr->amp != nil)
|
if(ctlr->amp != nil)
|
||||||
vt[0].range = getoutamprange(ctlr->amp);
|
vt[Vmaster].range = getoutamprange(ctlr->amp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long
|
static long
|
||||||
hdavolread(Audio *adev, void *a, long n, vlong)
|
hdavolread(Audio *adev, void *a, long n, vlong)
|
||||||
{
|
{
|
||||||
Volume voltab[2];
|
Volume voltab[Nvol+1];
|
||||||
fillvoltab(adev->ctlr, voltab);
|
fillvoltab(adev->ctlr, voltab);
|
||||||
return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
|
return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
|
||||||
}
|
}
|
||||||
|
@ -1136,7 +1177,7 @@ hdavolread(Audio *adev, void *a, long n, vlong)
|
||||||
static long
|
static long
|
||||||
hdavolwrite(Audio *adev, void *a, long n, vlong)
|
hdavolwrite(Audio *adev, void *a, long n, vlong)
|
||||||
{
|
{
|
||||||
Volume voltab[2];
|
Volume voltab[Nvol+1];
|
||||||
fillvoltab(adev->ctlr, voltab);
|
fillvoltab(adev->ctlr, voltab);
|
||||||
return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
|
return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
|
||||||
}
|
}
|
||||||
|
@ -1342,6 +1383,7 @@ hdareset(Audio *adev)
|
||||||
|
|
||||||
Found:
|
Found:
|
||||||
adev->ctlr = ctlr;
|
adev->ctlr = ctlr;
|
||||||
|
ctlr->adev = adev;
|
||||||
|
|
||||||
irq = p->intl;
|
irq = p->intl;
|
||||||
tbdf = p->tbdf;
|
tbdf = p->tbdf;
|
||||||
|
|
|
@ -28,6 +28,7 @@ enum
|
||||||
Vigain,
|
Vigain,
|
||||||
Vogain,
|
Vogain,
|
||||||
Vspeed,
|
Vspeed,
|
||||||
|
Vdelay,
|
||||||
Nvol,
|
Nvol,
|
||||||
|
|
||||||
Blocksize = 4096,
|
Blocksize = 4096,
|
||||||
|
@ -94,6 +95,7 @@ static Volume voltab[] = {
|
||||||
[Vigain] "recgain", 0x3f, 0xff, Stereo, 0,
|
[Vigain] "recgain", 0x3f, 0xff, Stereo, 0,
|
||||||
[Vogain] "outgain", 0x41, 0xff, Stereo, 0,
|
[Vogain] "outgain", 0x41, 0xff, Stereo, 0,
|
||||||
[Vspeed] "speed", 0, 0, Absolute, 0,
|
[Vspeed] "speed", 0, 0, Absolute, 0,
|
||||||
|
[Vdelay] "delay", 0, 0, Absolute, 0,
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -239,15 +241,21 @@ mxsetvol(Audio *adev, int x, int a[2])
|
||||||
Ctlr *ctlr = adev->ctlr;
|
Ctlr *ctlr = adev->ctlr;
|
||||||
Volume *vol;
|
Volume *vol;
|
||||||
|
|
||||||
if(x == Vspeed){
|
|
||||||
ctlr->lvol[x] = ctlr->rvol[x] = a[0];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vol = voltab+x;
|
vol = voltab+x;
|
||||||
blaster = &ctlr->blaster;
|
blaster = &ctlr->blaster;
|
||||||
ilock(blaster);
|
ilock(blaster);
|
||||||
switch(vol->type){
|
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:
|
case Stereo:
|
||||||
ctlr->rvol[x] = a[1];
|
ctlr->rvol[x] = a[1];
|
||||||
mxcmd(blaster, vol->reg+1, a[1]);
|
mxcmd(blaster, vol->reg+1, a[1]);
|
||||||
|
@ -314,7 +322,7 @@ sb16startdma(Ctlr *ctlr)
|
||||||
sbcmd(blaster, 0x42); /* input sampling rate */
|
sbcmd(blaster, 0x42); /* input sampling rate */
|
||||||
else
|
else
|
||||||
sbcmd(blaster, 0x41); /* output sampling rate */
|
sbcmd(blaster, 0x41); /* output sampling rate */
|
||||||
speed = ctlr->lvol[Vspeed];
|
speed = ctlr->adev->speed;
|
||||||
sbcmd(blaster, speed>>8);
|
sbcmd(blaster, speed>>8);
|
||||||
sbcmd(blaster, speed);
|
sbcmd(blaster, speed);
|
||||||
|
|
||||||
|
@ -380,7 +388,7 @@ ess1688startdma(Ctlr *ctlr)
|
||||||
/*
|
/*
|
||||||
* Set the speed.
|
* Set the speed.
|
||||||
*/
|
*/
|
||||||
speed = ctlr->lvol[Vspeed];
|
speed = ctlr->adev->speed;
|
||||||
if(speed < 4000)
|
if(speed < 4000)
|
||||||
speed = 4000;
|
speed = 4000;
|
||||||
else if(speed > 48000)
|
else if(speed > 48000)
|
||||||
|
@ -524,6 +532,14 @@ anybuf(void *arg)
|
||||||
return available(&ctlr->ring) || inactive(ctlr);
|
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
|
static long
|
||||||
audiowrite(Audio *adev, void *vp, long n, vlong)
|
audiowrite(Audio *adev, void *vp, long n, vlong)
|
||||||
{
|
{
|
||||||
|
@ -546,6 +562,7 @@ audiowrite(Audio *adev, void *vp, long n, vlong)
|
||||||
}
|
}
|
||||||
p += n;
|
p += n;
|
||||||
}
|
}
|
||||||
|
sleep(&ctlr->vous, ratebuf, ctlr);
|
||||||
return p - (uchar*)vp;
|
return p - (uchar*)vp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,9 @@ struct Audio
|
||||||
long (*status)(Audio *, void *, long, vlong);
|
long (*status)(Audio *, void *, long, vlong);
|
||||||
long (*buffered)(Audio *);
|
long (*buffered)(Audio *);
|
||||||
|
|
||||||
|
int delay;
|
||||||
|
int speed;
|
||||||
|
|
||||||
int ctlrno;
|
int ctlrno;
|
||||||
Audio *next;
|
Audio *next;
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,7 +38,7 @@ enum {
|
||||||
static Dirtab audiodir[] = {
|
static Dirtab audiodir[] = {
|
||||||
".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
|
".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
|
||||||
"audio", {Qaudio}, 0, 0666,
|
"audio", {Qaudio}, 0, 0666,
|
||||||
"audioctl", {Qaudioctl}, 0, 0666,
|
"audioctl", {Qaudioctl}, 0, 0222,
|
||||||
"audiostat", {Qaudiostatus}, 0, 0444,
|
"audiostat", {Qaudiostatus}, 0, 0444,
|
||||||
"volume", {Qvolume}, 0, 0666,
|
"volume", {Qvolume}, 0, 0666,
|
||||||
};
|
};
|
||||||
|
@ -140,27 +140,21 @@ audioattach(char *spec)
|
||||||
|
|
||||||
i = 1<<adev->ctlrno;
|
i = 1<<adev->ctlrno;
|
||||||
if((attached & i) == 0 && adev->volwrite){
|
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;
|
||||||
if(!waserror()){
|
for(i=0; i<nelem(settings); i++){
|
||||||
adev->volwrite(adev, ac->buf, strlen(ac->buf), 0);
|
strcpy(ac->buf, settings[i]);
|
||||||
poperror();
|
if(!waserror()){
|
||||||
}
|
adev->volwrite(adev, ac->buf, strlen(ac->buf), 0);
|
||||||
strcpy(ac->buf, "master 100");
|
poperror();
|
||||||
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:
|
case Qaudio:
|
||||||
fn = adev->read;
|
fn = adev->read;
|
||||||
break;
|
break;
|
||||||
case Qaudioctl:
|
|
||||||
fn = adev->ctl;
|
|
||||||
break;
|
|
||||||
case Qaudiostatus:
|
case Qaudiostatus:
|
||||||
fn = adev->status;
|
fn = adev->status;
|
||||||
break;
|
break;
|
||||||
|
@ -221,7 +212,6 @@ audioread(Chan *c, void *a, long n, vlong off)
|
||||||
nexterror();
|
nexterror();
|
||||||
}
|
}
|
||||||
switch((ulong)c->qid.path){
|
switch((ulong)c->qid.path){
|
||||||
case Qaudioctl:
|
|
||||||
case Qaudiostatus:
|
case Qaudiostatus:
|
||||||
case Qvolume:
|
case Qvolume:
|
||||||
/* generate the text on first read */
|
/* generate the text on first read */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue