diff --git a/sys/src/9/pc/audioac97.c b/sys/src/9/pc/audioac97.c index ba8ff6777..2ea734676 100644 --- a/sys/src/9/pc/audioac97.c +++ b/sys/src/9/pc/audioac97.c @@ -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; diff --git a/sys/src/9/pc/audioac97mix.c b/sys/src/9/pc/audioac97mix.c index e6ef52a58..6d12a46a3 100644 --- a/sys/src/9/pc/audioac97mix.c +++ b/sys/src/9/pc/audioac97mix.c @@ -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: - 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; case Left: v = (vol->range - a[0]) & 0x7f; diff --git a/sys/src/9/pc/audiohda.c b/sys/src/9/pc/audiohda.c index a3b10ec6e..679bf9c25 100644 --- a/sys/src/9/pc/audiohda.c +++ b/sys/src/9/pc/audiohda.c @@ -277,7 +277,8 @@ struct Ctlr { Lock; /* interrupt lock */ 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; - 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; } static int -hdasetvol(Audio *adev, int, int a[2]) +hdasetvol(Audio *adev, int x, int a[2]) { 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; } @@ -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; diff --git a/sys/src/9/pc/audiosb16.c b/sys/src/9/pc/audiosb16.c index 3f6d8d682..90d058185 100644 --- a/sys/src/9/pc/audiosb16.c +++ b/sys/src/9/pc/audiosb16.c @@ -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; } diff --git a/sys/src/9/port/audioif.h b/sys/src/9/port/audioif.h index f8431fe3e..6ec66e319 100644 --- a/sys/src/9/port/audioif.h +++ b/sys/src/9/port/audioif.h @@ -21,6 +21,9 @@ struct Audio long (*status)(Audio *, void *, long, vlong); long (*buffered)(Audio *); + int delay; + int speed; + int ctlrno; Audio *next; }; diff --git a/sys/src/9/port/devaudio.c b/sys/src/9/port/devaudio.c index 193b9c9f7..783113b90 100644 --- a/sys/src/9/port/devaudio.c +++ b/sys/src/9/port/devaudio.c @@ -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<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"); - 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(); + attached |= i; + for(i=0; ibuf, settings[i]); + 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 */