audio/hda: stereo mixing

This commit is contained in:
ment 2011-06-28 01:22:34 +02:00
parent 7b6675ff1a
commit 59f388e947

View file

@ -202,8 +202,14 @@ enum {
Asetleft = 1<<13, Asetleft = 1<<13,
Asetright = 1<<12, Asetright = 1<<12,
Asetmute = 1<<7, Asetmute = 1<<7,
Aidx = 8, Asetidx = 8,
Agetin = 0<<15,
Agetout = 1<<15,
Agetleft = 1<<13,
Agetright = 1<<15,
Agetidx = 0,
Again = 0, Again = 0,
Againmask = 0x7f,
Getconvfmt = 0xa, Getconvfmt = 0xa,
Setconvfmt = 0x2, Setconvfmt = 0x2,
}; };
@ -473,78 +479,74 @@ newnid(Id id, uint nid)
return id; return id;
} }
/* vol is 0...127 or ~0 for 0dB; mute is 0/1 */ static uint
static void getoutamprange(Widget *w)
setoutamp(Widget *w, int mute, uint vol)
{ {
uint q, r; uint r;
uint zerodb, range;
if((w->cap & Woutampcap) == 0)
return;
r = cmd(w->id, Getparm, Outampcap); r = cmd(w->id, Getparm, Outampcap);
range = (r >> 8) & 0x7f; return (r >> 8) & 0x7f;
zerodb = r & 127;
q = Asetout | Asetleft | Asetright;
if(mute)
q |= Asetmute;
else if(vol == ~0)
q |= zerodb << Again;
else if(range > 0)
q |= (range * vol / 128) << Again;
cmd(w->id, Setamp, q);
} }
static void static void
getoutamp(Widget *w, int v[2]) getoutamp(Widget *w, int vol[2])
{ {
uint q, r, range; vol[0] = vol[1] = 0;
v[0] = 0;
v[1] = 0;
if((w->cap & Woutampcap) == 0) if((w->cap & Woutampcap) == 0)
return; return;
vol[0] = cmd(w->id, Getamp, Agetout | Agetleft) & Againmask;
r = cmd(w->id, Getparm, Outampcap); vol[1] = cmd(w->id, Getamp, Agetout | Agetright) & Againmask;
range = (r >> 8) & 0x7f;
q = (1 << 15) | (1 << 13);
r = cmd(w->id, Getamp, q);
v[0] = (r & 0x7f) * 128 / range;
q = (1 << 15) | (0 << 13);
r = cmd(w->id, Getamp, q);
v[1] = (r & 0x7f) * 128 / range;
} }
/* vol is 0...127 or ~0 for 0dB; mute is 0/1; in is widget or nil for all */ /* vol is 0...range or nil for 0dB; mute is 0/1 */
static void static void
setinamp(Widget *w, Widget *in, int mute, uint vol) setoutamp(Widget *w, int mute, int *vol)
{ {
uint q, r, i; uint q, r, i;
uint zerodb, range; uint zerodb;
if((w->cap & Woutampcap) == 0)
return;
r = cmd(w->id, Getparm, Outampcap);
zerodb = r & 0x7f;
for(i=0; i<2; i++){
q = Asetout | (i == 0 ? Asetleft : Asetright);
if(mute)
q |= Asetmute;
else if(vol == nil)
q |= zerodb << Again;
else
q |= vol[i] << Again;
cmd(w->id, Setamp, q);
}
}
/* vol is 0...range or nil for 0dB; mute is 0/1; in is widget or nil for all */
static void
setinamp(Widget *w, Widget *in, int mute, int *vol)
{
uint q, r, i, j;
uint zerodb;
if((w->cap & Winampcap) == 0) if((w->cap & Winampcap) == 0)
return; return;
r = cmd(w->id, Getparm, Inampcap); r = cmd(w->id, Getparm, Inampcap);
range = (r >> 8) & 0x7f; zerodb = r & 0x7f;
zerodb = r & 127;
q = Asetin | Asetleft | Asetright; for(i=0; i<2; i++){
q = Asetin | (i == 0 ? Asetleft : Asetright);
if(mute) if(mute)
q |= Asetmute; q |= Asetmute;
else if(vol == ~0) else if(vol == nil)
q |= zerodb << Again; q |= zerodb << Again;
else if(range > 0) else
q |= (range * vol / 128) << Again; q |= vol[i] << Again;
for(i=0; i<w->nlist; i++){ for(j=0; j<w->nlist; j++){
if(in == nil || w->list[i] == in) if(in == nil || w->list[j] == in)
cmd(w->id, Setamp, q | (i << Aidx)); cmd(w->id, Setamp, q | (j << Asetidx));
}
} }
} }
@ -585,14 +587,14 @@ connectpath(Widget *src, Widget *dst, uint stream)
uint i; uint i;
for(w=src->fg->first; w != nil; w=w->next){ for(w=src->fg->first; w != nil; w=w->next){
setoutamp(w, 1, 0); setoutamp(w, 1, nil);
setinamp(w, nil, 1, 0); setinamp(w, nil, 1, nil);
cmd(w->id, Setstream, 0); cmd(w->id, Setstream, 0);
} }
for(w=dst; w != src; w=v){ for(w=dst; w != src; w=v){
v = w->from; v = w->from;
setoutamp(w, 0, ~0); setoutamp(w, 0, nil);
setinamp(v, w, 0, ~0); setinamp(v, w, 0, nil);
if(v->type == Waout || v->type == Wamix) if(v->type == Waout || v->type == Wamix)
continue; continue;
if(v->nlist == 1) if(v->nlist == 1)
@ -601,7 +603,7 @@ connectpath(Widget *src, Widget *dst, uint stream)
; ;
cmd(v->id, Setconn, i); cmd(v->id, Setconn, i);
} }
setoutamp(src, 0, ~0); setoutamp(src, 0, nil);
cmd(src->id, Setpinctl, Pinctlout); cmd(src->id, Setpinctl, Pinctlout);
cmd(dst->id, Setstream, (stream << 4) | 0); cmd(dst->id, Setstream, (stream << 4) | 0);
cmd(dst->id, Setconvfmt, (1 << 14) | (1 << 4) | 1); cmd(dst->id, Setconvfmt, (1 << 14) | (1 << 4) | 1);
@ -1044,9 +1046,7 @@ hdactl(Audio *adev, void *va, long n, vlong)
if(ntok <= 0) if(ntok <= 0)
continue; continue;
if(cistrcmp(tok[0], "pin") == 0 && ntok == 2){ if(cistrcmp(tok[0], "pin") == 0 && ntok == 2){
qlock(ctlr);
connectpin(ctlr, strtoul(tok[1], 0, 0)); connectpin(ctlr, strtoul(tok[1], 0, 0));
qunlock(ctlr);
}else }else
error(Ebadctl); error(Ebadctl);
} }
@ -1101,12 +1101,8 @@ static int
hdagetvol(Audio *adev, int, int a[2]) hdagetvol(Audio *adev, int, int a[2])
{ {
Ctlr *ctlr = adev->ctlr; Ctlr *ctlr = adev->ctlr;
if(ctlr->amp != nil)
if(ctlr->amp == nil)
return -1;
qlock(ctlr);
getoutamp(ctlr->amp, a); getoutamp(ctlr->amp, a);
qunlock(ctlr);
return 0; return 0;
} }
@ -1114,24 +1110,32 @@ static int
hdasetvol(Audio *adev, int, int a[2]) hdasetvol(Audio *adev, int, int a[2])
{ {
Ctlr *ctlr = adev->ctlr; Ctlr *ctlr = adev->ctlr;
if(ctlr->amp != nil)
if(ctlr->amp == nil) setoutamp(ctlr->amp, 0, a);
return -1;
qlock(ctlr);
setoutamp(ctlr->amp, 0, a[0]);
qunlock(ctlr);
return 0; return 0;
} }
static void
fillvoltab(Ctlr *ctlr, Volume *vt)
{
memmove(vt, voltab, sizeof(voltab));
if(ctlr->amp != nil)
vt[0].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];
fillvoltab(adev->ctlr, voltab);
return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0); return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
} }
static long static long
hdavolwrite(Audio *adev, void *a, long n, vlong) hdavolwrite(Audio *adev, void *a, long n, vlong)
{ {
Volume voltab[2];
fillvoltab(adev->ctlr, voltab);
return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0); return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
} }