1/*************************************************************************** 2 * au88x0_a3d.c 3 * 4 * Fri Jul 18 14:16:22 2003 5 * Copyright 2003 mjander 6 * mjander@users.sourceforge.net 7 * 8 * A3D. You may think i'm crazy, but this may work someday. Who knows... 9 ****************************************************************************/ 10 11/* 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU Library General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 25 */ 26 27#include "au88x0_a3d.h" 28#include "au88x0_a3ddata.c" 29#include "au88x0_xtalk.h" 30#include "au88x0.h" 31 32static void 33a3dsrc_SetTimeConsts(a3dsrc_t * a, short HrtfTrack, short ItdTrack, 34 short GTrack, short CTrack) 35{ 36 vortex_t *vortex = (vortex_t *) (a->vortex); 37 hwwrite(vortex->mmio, 38 a3d_addrA(a->slice, a->source, A3D_A_HrtfTrackTC), HrtfTrack); 39 hwwrite(vortex->mmio, 40 a3d_addrA(a->slice, a->source, A3D_A_ITDTrackTC), ItdTrack); 41 hwwrite(vortex->mmio, 42 a3d_addrA(a->slice, a->source, A3D_A_GainTrackTC), GTrack); 43 hwwrite(vortex->mmio, 44 a3d_addrA(a->slice, a->source, A3D_A_CoeffTrackTC), CTrack); 45} 46 47/* Atmospheric absorbtion. */ 48 49static void 50a3dsrc_SetAtmosTarget(a3dsrc_t * a, short aa, short b, short c, short d, 51 short e) 52{ 53 vortex_t *vortex = (vortex_t *) (a->vortex); 54 hwwrite(vortex->mmio, 55 a3d_addrB(a->slice, a->source, A3D_B_A21Target), 56 (e << 0x10) | d); 57 hwwrite(vortex->mmio, 58 a3d_addrB(a->slice, a->source, A3D_B_B10Target), 59 (b << 0x10) | aa); 60 hwwrite(vortex->mmio, 61 a3d_addrB(a->slice, a->source, A3D_B_B2Target), c); 62} 63 64static void 65a3dsrc_SetAtmosCurrent(a3dsrc_t * a, short aa, short b, short c, short d, 66 short e) 67{ 68 vortex_t *vortex = (vortex_t *) (a->vortex); 69 hwwrite(vortex->mmio, 70 a3d_addrB(a->slice, a->source, A3D_B_A12Current), 71 (e << 0x10) | d); 72 hwwrite(vortex->mmio, 73 a3d_addrB(a->slice, a->source, A3D_B_B01Current), 74 (b << 0x10) | aa); 75 hwwrite(vortex->mmio, 76 a3d_addrB(a->slice, a->source, A3D_B_B2Current), c); 77} 78 79static void 80a3dsrc_SetAtmosState(a3dsrc_t * a, short x1, short x2, short y1, short y2) 81{ 82 vortex_t *vortex = (vortex_t *) (a->vortex); 83 hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x1), x1); 84 hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x2), x2); 85 hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y1), y1); 86 hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y2), y2); 87} 88 89/* HRTF */ 90 91static void 92a3dsrc_SetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b) 93{ 94 vortex_t *vortex = (vortex_t *) (a->vortex); 95 int i; 96 97 for (i = 0; i < HRTF_SZ; i++) 98 hwwrite(vortex->mmio, 99 a3d_addrB(a->slice, a->source, 100 A3D_B_HrtfTarget) + (i << 2), 101 (b[i] << 0x10) | aa[i]); 102} 103 104static void 105a3dsrc_SetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b) 106{ 107 vortex_t *vortex = (vortex_t *) (a->vortex); 108 int i; 109 110 for (i = 0; i < HRTF_SZ; i++) 111 hwwrite(vortex->mmio, 112 a3d_addrB(a->slice, a->source, 113 A3D_B_HrtfCurrent) + (i << 2), 114 (b[i] << 0x10) | aa[i]); 115} 116 117static void 118a3dsrc_SetHrtfState(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b) 119{ 120 vortex_t *vortex = (vortex_t *) (a->vortex); 121 int i; 122 123 for (i = 0; i < HRTF_SZ; i++) 124 hwwrite(vortex->mmio, 125 a3d_addrB(a->slice, a->source, 126 A3D_B_HrtfDelayLine) + (i << 2), 127 (b[i] << 0x10) | aa[i]); 128} 129 130static void a3dsrc_SetHrtfOutput(a3dsrc_t * a, short left, short right) 131{ 132 vortex_t *vortex = (vortex_t *) (a->vortex); 133 hwwrite(vortex->mmio, 134 a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL), left); 135 hwwrite(vortex->mmio, 136 a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR), right); 137} 138 139 140/* Interaural Time Difference. 141 * "The other main clue that humans use to locate sounds, is called 142 * Interaural Time Difference (ITD). The differences in distance from 143 * the sound source to a listeners ears means that the sound will 144 * reach one ear slightly before the other....", found somewhere with google.*/ 145static void a3dsrc_SetItdTarget(a3dsrc_t * a, short litd, short ritd) 146{ 147 vortex_t *vortex = (vortex_t *) (a->vortex); 148 149 if (litd < 0) 150 litd = 0; 151 if (litd > 0x57FF) 152 litd = 0x57FF; 153 if (ritd < 0) 154 ritd = 0; 155 if (ritd > 0x57FF) 156 ritd = 0x57FF; 157 hwwrite(vortex->mmio, 158 a3d_addrB(a->slice, a->source, A3D_B_ITDTarget), 159 (ritd << 0x10) | litd); 160 //hwwrite(vortex->mmio, addr(0x191DF+5, this04, this08), (ritd<<0x10)|litd); 161} 162 163static void a3dsrc_SetItdCurrent(a3dsrc_t * a, short litd, short ritd) 164{ 165 vortex_t *vortex = (vortex_t *) (a->vortex); 166 167 if (litd < 0) 168 litd = 0; 169 if (litd > 0x57FF) 170 litd = 0x57FF; 171 if (ritd < 0) 172 ritd = 0; 173 if (ritd > 0x57FF) 174 ritd = 0x57FF; 175 hwwrite(vortex->mmio, 176 a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent), 177 (ritd << 0x10) | litd); 178 //hwwrite(vortex->mmio, addr(0x191DF+1, this04, this08), (ritd<<0x10)|litd); 179} 180 181static void a3dsrc_SetItdDline(a3dsrc_t * a, a3d_ItdDline_t const dline) 182{ 183 vortex_t *vortex = (vortex_t *) (a->vortex); 184 int i; 185 /* 45 != 40 -> Check this ! */ 186 for (i = 0; i < DLINE_SZ; i++) 187 hwwrite(vortex->mmio, 188 a3d_addrA(a->slice, a->source, 189 A3D_A_ITDDelayLine) + (i << 2), dline[i]); 190} 191 192/* This is may be used for ILD Interaural Level Difference. */ 193 194static void a3dsrc_SetGainTarget(a3dsrc_t * a, short left, short right) 195{ 196 vortex_t *vortex = (vortex_t *) (a->vortex); 197 hwwrite(vortex->mmio, 198 a3d_addrB(a->slice, a->source, A3D_B_GainTarget), 199 (right << 0x10) | left); 200} 201 202static void a3dsrc_SetGainCurrent(a3dsrc_t * a, short left, short right) 203{ 204 vortex_t *vortex = (vortex_t *) (a->vortex); 205 hwwrite(vortex->mmio, 206 a3d_addrB(a->slice, a->source, A3D_B_GainCurrent), 207 (right << 0x10) | left); 208} 209 210/* Generic A3D stuff */ 211 212static void a3dsrc_SetA3DSampleRate(a3dsrc_t * a, int sr) 213{ 214 vortex_t *vortex = (vortex_t *) (a->vortex); 215 int esp0 = 0; 216 217 esp0 = (((esp0 & 0x7fffffff) | 0xB8000000) & 0x7) | ((sr & 0x1f) << 3); 218 hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), esp0); 219 //hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), esp0); 220} 221 222static void a3dsrc_EnableA3D(a3dsrc_t * a) 223{ 224 vortex_t *vortex = (vortex_t *) (a->vortex); 225 hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), 226 0xF0000001); 227 //hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), 0xF0000001); 228} 229 230static void a3dsrc_DisableA3D(a3dsrc_t * a) 231{ 232 vortex_t *vortex = (vortex_t *) (a->vortex); 233 hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), 234 0xF0000000); 235} 236 237static void a3dsrc_SetA3DControlReg(a3dsrc_t * a, unsigned long ctrl) 238{ 239 vortex_t *vortex = (vortex_t *) (a->vortex); 240 hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), ctrl); 241} 242 243static void a3dsrc_SetA3DPointerReg(a3dsrc_t * a, unsigned long ptr) 244{ 245 vortex_t *vortex = (vortex_t *) (a->vortex); 246 hwwrite(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd), ptr); 247} 248 249static void a3dsrc_ZeroSliceIO(a3dsrc_t * a) 250{ 251 vortex_t *vortex = (vortex_t *) (a->vortex); 252 int i; 253 254 for (i = 0; i < 8; i++) 255 hwwrite(vortex->mmio, 256 A3D_SLICE_VDBDest + 257 ((((a->slice) << 0xb) + i) << 2), 0); 258 for (i = 0; i < 4; i++) 259 hwwrite(vortex->mmio, 260 A3D_SLICE_VDBSource + 261 ((((a->slice) << 0xb) + i) << 2), 0); 262} 263 264/* Reset Single A3D source. */ 265static void a3dsrc_ZeroState(a3dsrc_t * a) 266{ 267 /* 268 printk(KERN_DEBUG "vortex: ZeroState slice: %d, source %d\n", 269 a->slice, a->source); 270 */ 271 a3dsrc_SetAtmosState(a, 0, 0, 0, 0); 272 a3dsrc_SetHrtfState(a, A3dHrirZeros, A3dHrirZeros); 273 a3dsrc_SetItdDline(a, A3dItdDlineZeros); 274 a3dsrc_SetHrtfOutput(a, 0, 0); 275 a3dsrc_SetTimeConsts(a, 0, 0, 0, 0); 276 277 a3dsrc_SetAtmosCurrent(a, 0, 0, 0, 0, 0); 278 a3dsrc_SetAtmosTarget(a, 0, 0, 0, 0, 0); 279 a3dsrc_SetItdCurrent(a, 0, 0); 280 a3dsrc_SetItdTarget(a, 0, 0); 281 a3dsrc_SetGainCurrent(a, 0, 0); 282 a3dsrc_SetGainTarget(a, 0, 0); 283 284 a3dsrc_SetHrtfCurrent(a, A3dHrirZeros, A3dHrirZeros); 285 a3dsrc_SetHrtfTarget(a, A3dHrirZeros, A3dHrirZeros); 286} 287 288/* Reset entire A3D engine */ 289static void a3dsrc_ZeroStateA3D(a3dsrc_t * a) 290{ 291 int i, var, var2; 292 293 if ((a->vortex) == NULL) { 294 printk(KERN_ERR "vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n"); 295 return; 296 } 297 298 a3dsrc_SetA3DControlReg(a, 0); 299 a3dsrc_SetA3DPointerReg(a, 0); 300 301 var = a->slice; 302 var2 = a->source; 303 for (i = 0; i < 4; i++) { 304 a->slice = i; 305 a3dsrc_ZeroSliceIO(a); 306 //a3dsrc_ZeroState(a); 307 } 308 a->source = var2; 309 a->slice = var; 310} 311 312/* Program A3D block as pass through */ 313static void a3dsrc_ProgramPipe(a3dsrc_t * a) 314{ 315 a3dsrc_SetTimeConsts(a, 0, 0, 0, 0); 316 a3dsrc_SetAtmosCurrent(a, 0, 0x4000, 0, 0, 0); 317 a3dsrc_SetAtmosTarget(a, 0x4000, 0, 0, 0, 0); 318 a3dsrc_SetItdCurrent(a, 0, 0); 319 a3dsrc_SetItdTarget(a, 0, 0); 320 a3dsrc_SetGainCurrent(a, 0x7fff, 0x7fff); 321 a3dsrc_SetGainTarget(a, 0x7fff, 0x7fff); 322 323 /* SET HRTF HERE */ 324 325 /* Single spike leads to identity transfer function. */ 326 a3dsrc_SetHrtfCurrent(a, A3dHrirImpulse, A3dHrirImpulse); 327 a3dsrc_SetHrtfTarget(a, A3dHrirImpulse, A3dHrirImpulse); 328 329 /* Test: Sounds saturated. */ 330 //a3dsrc_SetHrtfCurrent(a, A3dHrirSatTest, A3dHrirSatTest); 331 //a3dsrc_SetHrtfTarget(a, A3dHrirSatTest, A3dHrirSatTest); 332} 333 334/* VDB = Vortex audio Dataflow Bus */ 335 336/* A3D HwSource stuff. */ 337 338static void vortex_A3dSourceHw_Initialize(vortex_t * v, int source, int slice) 339{ 340 a3dsrc_t *a3dsrc = &(v->a3d[source + (slice * 4)]); 341 //a3dsrc_t *a3dsrc = &(v->a3d[source + (slice*4)]); 342 343 a3dsrc->vortex = (void *)v; 344 a3dsrc->source = source; /* source */ 345 a3dsrc->slice = slice; /* slice */ 346 a3dsrc_ZeroState(a3dsrc); 347 /* Added by me. */ 348 a3dsrc_SetA3DSampleRate(a3dsrc, 0x11); 349} 350 351static int Vort3DRend_Initialize(vortex_t * v, unsigned short mode) 352{ 353 v->xt_mode = mode; /* this_14 */ 354 355 vortex_XtalkHw_init(v); 356 vortex_XtalkHw_SetGainsAllChan(v); 357 switch (v->xt_mode) { 358 case XT_SPEAKER0: 359 vortex_XtalkHw_ProgramXtalkNarrow(v); 360 break; 361 case XT_SPEAKER1: 362 vortex_XtalkHw_ProgramXtalkWide(v); 363 break; 364 default: 365 case XT_HEADPHONE: 366 vortex_XtalkHw_ProgramPipe(v); 367 break; 368 case XT_DIAMOND: 369 vortex_XtalkHw_ProgramDiamondXtalk(v); 370 break; 371 } 372 vortex_XtalkHw_SetSampleRate(v, 0x11); 373 vortex_XtalkHw_Enable(v); 374 return 0; 375} 376 377/* 3D Sound entry points. */ 378 379static int vortex_a3d_register_controls(vortex_t * vortex); 380static void vortex_a3d_unregister_controls(vortex_t * vortex); 381/* A3D base support init/shudown */ 382static void __devinit vortex_Vort3D_enable(vortex_t * v) 383{ 384 int i; 385 386 Vort3DRend_Initialize(v, XT_HEADPHONE); 387 for (i = 0; i < NR_A3D; i++) { 388 vortex_A3dSourceHw_Initialize(v, i % 4, i >> 2); 389 a3dsrc_ZeroStateA3D(&(v->a3d[0])); 390 } 391 /* Register ALSA controls */ 392 vortex_a3d_register_controls(v); 393} 394 395static void vortex_Vort3D_disable(vortex_t * v) 396{ 397 vortex_XtalkHw_Disable(v); 398 vortex_a3d_unregister_controls(v); 399} 400 401/* Make A3D subsystem connections. */ 402static void vortex_Vort3D_connect(vortex_t * v, int en) 403{ 404 int i; 405 406// Disable AU8810 routes, since they seem to be wrong (in au8810.h). 407#ifdef CHIP_AU8810 408 return; 409#endif 410 411 /* Alloc Xtalk mixin resources */ 412 v->mixxtlk[0] = 413 vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN); 414 if (v->mixxtlk[0] < 0) { 415 printk 416 ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n"); 417 return; 418 } 419 v->mixxtlk[1] = 420 vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN); 421 if (v->mixxtlk[1] < 0) { 422 printk 423 ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n"); 424 return; 425 } 426 427 /* Connect A3D -> XTALK */ 428 for (i = 0; i < 4; i++) { 429 // 2 outputs per each A3D slice. 430 vortex_route(v, en, 0x11, ADB_A3DOUT(i * 2), ADB_XTALKIN(i)); 431 vortex_route(v, en, 0x11, ADB_A3DOUT(i * 2) + 1, ADB_XTALKIN(5 + i)); 432 } 433 /* Connect XTalk -> mixer */ 434 vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_MIXIN(v->mixxtlk[0])); 435 vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_MIXIN(v->mixxtlk[1])); 436 vortex_connection_mixin_mix(v, en, v->mixxtlk[0], v->mixplayb[0], 0); 437 vortex_connection_mixin_mix(v, en, v->mixxtlk[1], v->mixplayb[1], 0); 438 vortex_mix_setinputvolumebyte(v, v->mixplayb[0], v->mixxtlk[0], 439 en ? MIX_DEFIGAIN : VOL_MIN); 440 vortex_mix_setinputvolumebyte(v, v->mixplayb[1], v->mixxtlk[1], 441 en ? MIX_DEFIGAIN : VOL_MIN); 442 if (VORTEX_IS_QUAD(v)) { 443 vortex_connection_mixin_mix(v, en, v->mixxtlk[0], 444 v->mixplayb[2], 0); 445 vortex_connection_mixin_mix(v, en, v->mixxtlk[1], 446 v->mixplayb[3], 0); 447 vortex_mix_setinputvolumebyte(v, v->mixplayb[2], 448 v->mixxtlk[0], 449 en ? MIX_DEFIGAIN : VOL_MIN); 450 vortex_mix_setinputvolumebyte(v, v->mixplayb[3], 451 v->mixxtlk[1], 452 en ? MIX_DEFIGAIN : VOL_MIN); 453 } 454} 455 456/* Initialize one single A3D source. */ 457static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en) 458{ 459 if (a->vortex == NULL) { 460 printk 461 ("vortex: Vort3D_InitializeSource: A3D source not initialized\n"); 462 return; 463 } 464 if (en) { 465 a3dsrc_ProgramPipe(a); 466 a3dsrc_SetA3DSampleRate(a, 0x11); 467 a3dsrc_SetTimeConsts(a, HrtfTCDefault, 468 ItdTCDefault, GainTCDefault, 469 CoefTCDefault); 470 /* Remark: zero gain is muted. */ 471 //a3dsrc_SetGainTarget(a,0,0); 472 //a3dsrc_SetGainCurrent(a,0,0); 473 a3dsrc_EnableA3D(a); 474 } else { 475 a3dsrc_DisableA3D(a); 476 a3dsrc_ZeroState(a); 477 } 478} 479 480/* Conversion of coordinates into 3D parameters. */ 481 482static void vortex_a3d_coord2hrtf(a3d_Hrtf_t hrtf, int *coord) 483{ 484 485} 486static void vortex_a3d_coord2itd(a3d_Itd_t itd, int *coord) 487{ 488 489} 490static void vortex_a3d_coord2ild(a3d_LRGains_t ild, int left, int right) 491{ 492 493} 494static void vortex_a3d_translate_filter(a3d_atmos_t filter, int *params) 495{ 496 497} 498 499/* ALSA control interface. */ 500 501static int 502snd_vortex_a3d_hrtf_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 503{ 504 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 505 uinfo->count = 6; 506 uinfo->value.integer.min = 0x00000000; 507 uinfo->value.integer.max = 0xffffffff; 508 return 0; 509} 510static int 511snd_vortex_a3d_itd_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 512{ 513 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 514 uinfo->count = 2; 515 uinfo->value.integer.min = 0x00000000; 516 uinfo->value.integer.max = 0xffffffff; 517 return 0; 518} 519static int 520snd_vortex_a3d_ild_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 521{ 522 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 523 uinfo->count = 2; 524 uinfo->value.integer.min = 0x00000000; 525 uinfo->value.integer.max = 0xffffffff; 526 return 0; 527} 528static int 529snd_vortex_a3d_filter_info(struct snd_kcontrol *kcontrol, 530 struct snd_ctl_elem_info *uinfo) 531{ 532 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 533 uinfo->count = 4; 534 uinfo->value.integer.min = 0x00000000; 535 uinfo->value.integer.max = 0xffffffff; 536 return 0; 537} 538 539static int 540snd_vortex_a3d_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 541{ 542 //a3dsrc_t *a = kcontrol->private_data; 543 /* No read yet. Would this be really useable/needed ? */ 544 545 return 0; 546} 547 548static int 549snd_vortex_a3d_hrtf_put(struct snd_kcontrol *kcontrol, 550 struct snd_ctl_elem_value *ucontrol) 551{ 552 a3dsrc_t *a = kcontrol->private_data; 553 int changed = 1, i; 554 int coord[6]; 555 for (i = 0; i < 6; i++) 556 coord[i] = ucontrol->value.integer.value[i]; 557 /* Translate orientation coordinates to a3d params. */ 558 vortex_a3d_coord2hrtf(a->hrtf[0], coord); 559 vortex_a3d_coord2hrtf(a->hrtf[1], coord); 560 a3dsrc_SetHrtfTarget(a, a->hrtf[0], a->hrtf[1]); 561 a3dsrc_SetHrtfCurrent(a, a->hrtf[0], a->hrtf[1]); 562 return changed; 563} 564 565static int 566snd_vortex_a3d_itd_put(struct snd_kcontrol *kcontrol, 567 struct snd_ctl_elem_value *ucontrol) 568{ 569 a3dsrc_t *a = kcontrol->private_data; 570 int coord[6]; 571 int i, changed = 1; 572 for (i = 0; i < 6; i++) 573 coord[i] = ucontrol->value.integer.value[i]; 574 /* Translate orientation coordinates to a3d params. */ 575 vortex_a3d_coord2itd(a->hrtf[0], coord); 576 vortex_a3d_coord2itd(a->hrtf[1], coord); 577 /* Inter aural time difference. */ 578 a3dsrc_SetItdTarget(a, a->itd[0], a->itd[1]); 579 a3dsrc_SetItdCurrent(a, a->itd[0], a->itd[1]); 580 a3dsrc_SetItdDline(a, a->dline); 581 return changed; 582} 583 584static int 585snd_vortex_a3d_ild_put(struct snd_kcontrol *kcontrol, 586 struct snd_ctl_elem_value *ucontrol) 587{ 588 a3dsrc_t *a = kcontrol->private_data; 589 int changed = 1; 590 int l, r; 591 /* There may be some scale tranlation needed here. */ 592 l = ucontrol->value.integer.value[0]; 593 r = ucontrol->value.integer.value[1]; 594 vortex_a3d_coord2ild(a->ild, l, r); 595 /* Left Right panning. */ 596 a3dsrc_SetGainTarget(a, l, r); 597 a3dsrc_SetGainCurrent(a, l, r); 598 return changed; 599} 600 601static int 602snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol, 603 struct snd_ctl_elem_value *ucontrol) 604{ 605 a3dsrc_t *a = kcontrol->private_data; 606 int i, changed = 1; 607 int params[6]; 608 for (i = 0; i < 6; i++) 609 params[i] = ucontrol->value.integer.value[i]; 610 /* Translate generic filter params to a3d filter params. */ 611 vortex_a3d_translate_filter(a->filter, params); 612 /* Atmospheric absorbtion and filtering. */ 613 a3dsrc_SetAtmosTarget(a, a->filter[0], 614 a->filter[1], a->filter[2], 615 a->filter[3], a->filter[4]); 616 a3dsrc_SetAtmosCurrent(a, a->filter[0], 617 a->filter[1], a->filter[2], 618 a->filter[3], a->filter[4]); 619 return changed; 620} 621 622static struct snd_kcontrol_new vortex_a3d_kcontrol __devinitdata = { 623 .iface = SNDRV_CTL_ELEM_IFACE_PCM, 624 .name = "Playback PCM advanced processing", 625 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 626 .info = snd_vortex_a3d_hrtf_info, 627 .get = snd_vortex_a3d_get, 628 .put = snd_vortex_a3d_hrtf_put, 629}; 630 631/* Control (un)registration. */ 632static int __devinit vortex_a3d_register_controls(vortex_t * vortex) 633{ 634 struct snd_kcontrol *kcontrol; 635 int err, i; 636 /* HRTF controls. */ 637 for (i = 0; i < NR_A3D; i++) { 638 if ((kcontrol = 639 snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL) 640 return -ENOMEM; 641 kcontrol->id.numid = CTRLID_HRTF; 642 kcontrol->info = snd_vortex_a3d_hrtf_info; 643 kcontrol->put = snd_vortex_a3d_hrtf_put; 644 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) 645 return err; 646 } 647 /* ITD controls. */ 648 for (i = 0; i < NR_A3D; i++) { 649 if ((kcontrol = 650 snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL) 651 return -ENOMEM; 652 kcontrol->id.numid = CTRLID_ITD; 653 kcontrol->info = snd_vortex_a3d_itd_info; 654 kcontrol->put = snd_vortex_a3d_itd_put; 655 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) 656 return err; 657 } 658 /* ILD (gains) controls. */ 659 for (i = 0; i < NR_A3D; i++) { 660 if ((kcontrol = 661 snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL) 662 return -ENOMEM; 663 kcontrol->id.numid = CTRLID_GAINS; 664 kcontrol->info = snd_vortex_a3d_ild_info; 665 kcontrol->put = snd_vortex_a3d_ild_put; 666 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) 667 return err; 668 } 669 /* Filter controls. */ 670 for (i = 0; i < NR_A3D; i++) { 671 if ((kcontrol = 672 snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL) 673 return -ENOMEM; 674 kcontrol->id.numid = CTRLID_FILTER; 675 kcontrol->info = snd_vortex_a3d_filter_info; 676 kcontrol->put = snd_vortex_a3d_filter_put; 677 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) 678 return err; 679 } 680 return 0; 681} 682 683static void vortex_a3d_unregister_controls(vortex_t * vortex) 684{ 685 686} 687 688/* End of File*/ 689