audio.c (15454B)
1 2 #include "audio.h" 3 4 #include "graph.h" 5 6 //------------ 7 extern void N64_wdd_location(char *wdd_location); 8 extern void N64_set_output_rate(u32 rate); 9 10 extern int wess_driver_num_dma_buffers; // 8005D948 11 extern int wess_driver_num_dma_messages; // 8005D94C 12 extern int wess_driver_dma_buffer_length; // 8005D950 13 extern int wess_driver_extra_samples; // 8005D954 14 extern int wess_driver_frame_lag; // 8005D958 15 extern int wess_driver_voices; // 8005D95C 16 extern int wess_driver_updates; // 8005D960 17 extern int wess_driver_sequences; // 8005D964 18 extern int wess_driver_tracks; // 8005D968 19 extern int wess_driver_gates; // 8005D96C 20 extern int wess_driver_iters; // 8005D970 21 extern int wess_driver_callbacks; // 8005D974 22 extern int wess_driver_max_trks_per_seq; // 8005D978 load_sequence_data:80039868(R), 23 extern int wess_driver_max_subs_per_trk; // 8005D97C 24 25 /* used by wesssys_exit */ 26 enum RestoreFlag {NoRestore,YesRestore}; 27 28 extern int wesssys_init(void); 29 extern void wesssys_exit(enum RestoreFlag rflag); 30 31 //------------ 32 33 #ifndef NOUSEWESSCODE 34 //------------ 35 AMAudioMgr __am; //800B4060 36 ALVoice *voice; //800B40E0 37 char *reverb_status; //800B40E4 38 //------------ 39 40 //------------ 41 AMDMAState dmaState; //800B40C0 42 AMDMABuffer *dmaBuffs; //800B40CC 43 u32 audFrameCt = 0; //8005D8B0 44 u32 nextDMA = 0; //8005D8B4 45 u32 curAcmdList = 0; //8005D8B8 46 u32 minFrameSize; //800B40D0 47 u32 frameSize; //800B40D4 48 u32 maxFrameSize; //800b40d8 49 u32 maxRSPCmds; //800B40DC 50 51 /* Queues and storage for use with audio DMA's */ 52 OSMesgQueue audDMAMessageQ; //800B40E8 53 OSIoMesg *audDMAIOMesgBuf; //800B4100 54 OSMesg *audDMAMessageBuf; //800B4104 55 56 u32 buf = 0; //8005D8BC 57 AudioInfo *lastInfo = 0; //8005D8C0 58 59 u32 init_completed = 0; //8005D8C4 60 61 #define NUM_DMA_MESSAGES 8 /* The maximum number of DMAs any one frame can have.*/ 62 OSMesgQueue wess_dmaMessageQ; //800b4108 63 OSMesg wess_dmaMessageBuf[NUM_DMA_MESSAGES];//800b4120 64 //------------ 65 66 int wess_memfill(void *dst, unsigned char fill, int count) // 8002E300 67 { 68 char *d; 69 70 d = (char *)dst; 71 while (count != 0) 72 { 73 *d++ = (unsigned char)fill; 74 count--; 75 } 76 return count; 77 } 78 79 int wess_rom_copy(char *src, char *dest, int len) // 8002E334 80 { 81 OSMesg dummyMesg; 82 OSIoMesg DMAIoMesgBuf; 83 84 if (init_completed != 0 && len != 0) 85 { 86 osInvalDCache((void *)dest, (s32)len); 87 osPiStartDma(&DMAIoMesgBuf, OS_MESG_PRI_HIGH, OS_READ, (u32)src, (void *)dest, (u32)len, &wess_dmaMessageQ); 88 osRecvMesg(&wess_dmaMessageQ, &dummyMesg, OS_MESG_BLOCK); 89 90 return len; 91 } 92 93 return 0; 94 } 95 96 /*LEAF(milli_to_param) 97 lui $at, 0x447A 98 mtc1 $a1, $f12 99 mtc1 $at, $f8 100 mtc1 $a0, $f4 101 div.s $f10, $f12, $f8 102 cvt.s.w $f6, $f4 103 mul.s $f16, $f6, $f10 104 cfc1 $t6, FCSR 105 nop 106 li $at, $t6, 3 107 xori $at, $at, 2 108 ctc1 $at, FCSR 109 li $at, 0xFFFFFFF8 110 cvt.w.s $f18, $f16 111 mfc1 $v0, $f18 112 ctc1 $t6, FCSR 113 and $t7, $v0, $at 114 jr $ra 115 move $v0, $t7 116 END(milli_to_param)*/ 117 118 s32 milli_to_param(register s32 paramvalue, register s32 rate) // 8002E3D0 119 { 120 register u32 fpstat, fpstatset, out; 121 122 #ifdef N64ASM 123 asm("lui $at, 0x447A\n"); 124 asm("mtc1 %0, $f12\n" ::"r"(rate));//mtc1 $a1, $f12 125 asm("mtc1 $at, $f8\n"); 126 asm("mtc1 %0, $f4\n" ::"r"(paramvalue));//mtc1 $a0, $f4 127 asm("div.s $f10, $f12, $f8\n"); 128 asm("cvt.s.w $f6, $f4\n"); 129 asm("mul.s $f16, $f6, $f10\n"); 130 // fetch the current floating-point control/status register 131 asm("cfc1 %0, $f31\n" :"=r"(fpstat)); 132 asm("nop\n"); 133 // enable round to negative infinity for floating point 134 //"li $at, $t6, 3\n" 135 asm("ori $at, %0, 3\n" ::"r"(fpstat));//# fpstat |= FPCSR_RM_RM; 136 asm("xori $at, $at, 2\n"); 137 asm("ctc1 $at, $f31\n"); 138 //asm("li $at, 0xFFFFFFF8\n"); 139 asm("cvt.w.s $f18, $f16\n"); 140 asm("mfc1 %0, $f18\n" :"=r"(out)); 141 // _Disable_ unimplemented operation exception for floating point. 142 asm("ctc1 %0, $f31\n" ::"r"(fpstat)); 143 144 return (s32)(out &~0x7); 145 #else 146 //No asm mode 147 148 /* 149 // fetch the current floating-point control/status register 150 fpstat = __osGetFpcCsr(); 151 // enable round to negative infinity for floating point 152 fpstatset = (fpstat | FPCSR_RM_RM) ^ 2; 153 // _Disable_ unimplemented operation exception for floating point. 154 __osSetFpcCsr(fpstatset); 155 */ 156 157 return (s32)((f32)paramvalue * ((f32)rate / 1000.0f)) &~0x7; 158 #endif 159 } 160 161 void wess_init(WessConfig *wessconfig) // 8002E41C 162 { 163 ALSynConfig config; 164 f32 samplerate; 165 s32 *params;//Custom reverb 166 int sections, section_pos; 167 168 // Create audio DMA thread... 169 osCreateMesgQueue(&wess_dmaMessageQ, wess_dmaMessageBuf, NUM_DMA_MESSAGES); 170 171 buf = 0; 172 lastInfo = NULL; 173 174 N64_wdd_location(wessconfig->wdd_location); 175 176 config.dmaproc = __amDmaNew; 177 config.maxPVoices = config.maxVVoices = wess_driver_voices; 178 config.maxUpdates = wess_driver_updates; 179 config.fxType = (ALFxId)wessconfig->reverb_id; 180 181 N64_set_output_rate(wessconfig->outputsamplerate); 182 config.outputRate = osAiSetFrequency(wessconfig->outputsamplerate); 183 184 config.heap = wessconfig->heap_ptr; 185 186 if (config.fxType == WESS_REVERB_CUSTOM) 187 { 188 /* set address reverb table*/ 189 params = wessconfig->revtbl_ptr; 190 191 samplerate = wessconfig->outputsamplerate; 192 if ((u32)samplerate < 0) { samplerate += 4.2949673e9; } 193 194 /* total allocated memory */ 195 params[1] = milli_to_param(params[1], (u32)samplerate); 196 197 /* total allocated memory -> params[0]*/ 198 section_pos = 0; 199 for (sections = 0; sections < params[0]; sections++) 200 { 201 samplerate = wessconfig->outputsamplerate; 202 if ((u32)samplerate < 0) { samplerate += 4.2949673e9; } 203 204 /* input */ 205 params[2 + section_pos] = milli_to_param(params[2 + section_pos], (u32)samplerate); 206 207 samplerate = wessconfig->outputsamplerate; 208 if ((u32)samplerate < 0) { samplerate += 4.2949673e9; } 209 210 /* output */ 211 params[3 + section_pos] = milli_to_param(params[3 + section_pos], (u32)samplerate); 212 213 section_pos += 8; 214 } 215 216 config.params = params; 217 } 218 219 amCreateAudioMgr(&config, wessconfig); 220 SSP_SeqpNew(); 221 wesssys_init(); 222 init_completed = 1; 223 } 224 225 226 /*-------------------*/ 227 /* Audio Manager API */ 228 /*-------------------*/ 229 230 void amCreateAudioMgr(ALSynConfig *config, WessConfig *wessconfig) // 8002E610 231 { 232 f32 fsize; 233 f32 fsize2; 234 int frameSize1; 235 int i; 236 237 /* 238 * Calculate the frame sample parameters from the 239 * video field rate and the output rate 240 */ 241 fsize = (f32)(config->outputRate) / wessconfig->audioframerate; 242 frameSize1 = (s32)fsize; 243 244 if (frameSize1 < 0) { 245 frameSize1 = -1; 246 } 247 248 fsize2 = (float)frameSize1; 249 if (frameSize1 < 0) { 250 fsize2 += 4294967296.0; 251 } 252 253 frameSize = frameSize1 + 1; 254 if (fsize <= fsize2) { 255 frameSize = frameSize1; 256 } 257 258 if (frameSize & 15) 259 frameSize = (frameSize & ~0xf) + 16; 260 261 minFrameSize = frameSize - 16; 262 maxFrameSize = frameSize + wess_driver_extra_samples + 16; 263 264 voice = (ALVoice *)alHeapAlloc(config->heap, 1, wess_driver_voices * sizeof(ALVoice)); 265 wess_memfill(voice, 0, wess_driver_voices * sizeof(ALVoice)); 266 267 reverb_status = (char *)alHeapAlloc(config->heap, 1, wess_driver_voices); 268 wess_memfill(reverb_status, 0, wess_driver_voices); 269 270 dmaBuffs = (AMDMABuffer *)alHeapAlloc(config->heap, 1, wess_driver_num_dma_buffers * sizeof(AMDMABuffer)); 271 wess_memfill(dmaBuffs, 0, wess_driver_num_dma_buffers * sizeof(AMDMABuffer)); 272 273 /* allocate buffers for voices */ 274 dmaBuffs[0].node.prev = 0; 275 dmaBuffs[0].node.next = 0; 276 277 for (i = 0; i < (wess_driver_num_dma_buffers - 1); i++) 278 { 279 alLink((ALLink *)&dmaBuffs[i + 1], (ALLink *)&dmaBuffs[i]); 280 dmaBuffs[i].ptr = (char *)alHeapAlloc(config->heap, 1, wess_driver_dma_buffer_length); 281 wess_memfill(dmaBuffs[i].ptr, 0, wess_driver_dma_buffer_length); 282 } 283 284 /* last buffer already linked, but still needs buffer */ 285 dmaBuffs[i].ptr = alHeapAlloc(config->heap, 1, wess_driver_dma_buffer_length); 286 wess_memfill(dmaBuffs[i].ptr, 0, wess_driver_dma_buffer_length); 287 288 for (i = 0; i < NUM_ACMD_LISTS; i++) 289 { 290 __am.ACMDList[i] = (Acmd*)alHeapAlloc(config->heap, 1, wessconfig->maxACMDSize * sizeof(Acmd)); 291 wess_memfill(__am.ACMDList[i], 0, wessconfig->maxACMDSize * sizeof(Acmd)); 292 } 293 294 maxRSPCmds = wessconfig->maxACMDSize; 295 296 /* initialize the done messages */ 297 for (i = 0; i < NUM_OUTPUT_BUFFERS; i++) 298 { 299 __am.audioInfo[i] = (AudioInfo *)alHeapAlloc(config->heap, 1, sizeof(AudioInfo)); 300 wess_memfill(__am.audioInfo[i], 0, sizeof(AudioInfo)); 301 302 /* allocate output buffer */ 303 __am.audioInfo[i]->data = alHeapAlloc(config->heap, 1, maxFrameSize << 2); 304 wess_memfill(__am.audioInfo[i]->data, 0, maxFrameSize << 2); 305 } 306 307 audDMAIOMesgBuf = alHeapAlloc(config->heap, 1, wess_driver_num_dma_messages * sizeof(OSIoMesg)); 308 wess_memfill(audDMAIOMesgBuf, 0, wess_driver_num_dma_messages * sizeof(OSIoMesg)); 309 310 audDMAMessageBuf = alHeapAlloc(config->heap, 1, wess_driver_num_dma_messages * sizeof(OSMesg)); 311 wess_memfill(audDMAMessageBuf, 0, wess_driver_num_dma_messages * sizeof(OSMesg)); 312 313 osCreateMesgQueue(&audDMAMessageQ, audDMAMessageBuf, wess_driver_num_dma_messages); 314 315 alInit(&__am.g, config); 316 } 317 318 OSTask * wess_work(void) // 8002EB2C 319 { 320 OSTask *validTask; 321 322 if (init_completed == 0) 323 return (OSTask *)NULL; 324 325 validTask = __amHandleFrameMsg(__am.audioInfo[buf]); 326 327 lastInfo = __am.audioInfo[buf]; 328 329 buf++; 330 if (buf == NUM_OUTPUT_BUFFERS) 331 buf = 0; 332 333 if (validTask) 334 curAcmdList ^= 1; /* swap which acmd list you use each frame */ 335 336 return validTask; 337 } 338 339 OSTask *__amHandleFrameMsg(AudioInfo *info) // 8002EBD8 340 { 341 s16 *audioPtr; 342 Acmd *cmdp; 343 s32 cmdLen; 344 int samplesLeft; 345 int check; 346 347 /* audFrameCnt updated here */ 348 __clearAudioDMA(); /* call once a frame, before doing alAudioFrame */ 349 350 audioPtr = (s16 *)osVirtualToPhysical(info->data); /* info->data addr of current buffer */ 351 352 /* set up the next DMA transfer from DRAM to the audio interface buffer. */ 353 /* lastInfo->data is the buffer used in the last audio frame. It should be full. */ 354 if (lastInfo) 355 { 356 osAiSetNextBuffer(lastInfo->data, lastInfo->frameSamples << 2); 357 } 358 359 /* calculate how many samples needed for this frame to keep the DAC full */ 360 /* this will vary slightly frame to frame, must recalculate every frame */ 361 samplesLeft = osAiGetLength() >> 2; /* divide by four, to convert bytes */ 362 363 /* to stereo 16 bit samples */ 364 info->frameSamples = ((frameSize - samplesLeft) + wess_driver_extra_samples & ~0xf) + 16; 365 366 /* no longer necessary to have extra samples, because the buffers */ 367 /* will be swapped exactly when the buffer runs out */ 368 /* info->frameSamples = frameSize; */ 369 370 if (info->frameSamples < minFrameSize) 371 info->frameSamples = minFrameSize; 372 373 cmdp = alAudioFrame(__am.ACMDList[curAcmdList], &cmdLen, audioPtr, info->frameSamples); 374 375 if (maxRSPCmds < cmdLen) 376 { 377 wess_error_callback("MAXRSPCMDS", 0, 0); 378 } 379 380 /* this is the task for the next audio frame */ 381 info->task.t.data_ptr = (u64 *)__am.ACMDList[curAcmdList]; 382 info->task.t.data_size = (u32)((int)(((int)cmdp - (int)__am.ACMDList[curAcmdList]) >> 3) << 3); 383 info->task.t.type = M_AUDTASK; 384 info->task.t.ucode_boot = (u64 *)rspbootTextStart; 385 info->task.t.ucode_boot_size = ((int)rspbootTextEnd - (int)rspbootTextStart); 386 info->task.t.flags = 0; 387 info->task.t.ucode = (u64 *)aspMainTextStart; 388 info->task.t.ucode_data = (u64 *)aspMainDataStart; 389 info->task.t.ucode_data_size = SP_UCODE_DATA_SIZE; 390 info->task.t.yield_data_ptr = NULL; 391 info->task.t.yield_data_size = 0; 392 393 return (OSTask *)&info->task; 394 } 395 396 s32 __amDMA(s32 addr, s32 len, void *state) // 8002ED74 397 { 398 char *foundBuffer; 399 s32 delta, addrEnd, buffEnd; 400 AMDMABuffer *dmaPtr, *lastDmaPtr; 401 402 lastDmaPtr = 0; 403 dmaPtr = dmaState.firstUsed; 404 addrEnd = addr+len; 405 406 /* first check to see if a currently existing buffer contains the 407 sample that you need. */ 408 while (dmaPtr) 409 { 410 buffEnd = dmaPtr->startAddr + wess_driver_dma_buffer_length; 411 if (dmaPtr->startAddr > addr) /* since buffers are ordered */ 412 break; /* abort if past possible */ 413 414 else if (addrEnd <= buffEnd) /* yes, found a buffer with samples */ 415 { 416 dmaPtr->lastFrame = audFrameCt; /* mark it used */ 417 foundBuffer = dmaPtr->ptr + addr - dmaPtr->startAddr; 418 return (int)osVirtualToPhysical(foundBuffer); 419 } 420 lastDmaPtr = dmaPtr; 421 dmaPtr = (AMDMABuffer*)dmaPtr->node.next; 422 } 423 424 /* get here, and you didn't find a buffer, so dma a new one */ 425 426 /* get a buffer from the free list */ 427 dmaPtr = dmaState.firstFree; 428 429 /* be sure you have a buffer, */ 430 /* if you don't have one, you're fucked */ 431 if (!(dmaPtr)) 432 { 433 lastDmaPtr = 0; 434 wess_error_callback("DMAPTRNULL", 0, 0); 435 return (int)osVirtualToPhysical(dmaState.firstUsed); 436 } 437 438 dmaState.firstFree = (AMDMABuffer*)dmaPtr->node.next; 439 alUnlink((ALLink*)dmaPtr); 440 441 /* add it to the used list */ 442 if (lastDmaPtr) /* if you have other dmabuffers used, add this one */ 443 { /* to the list, after the last one checked above */ 444 alLink((ALLink*)dmaPtr, (ALLink*)lastDmaPtr); 445 } 446 else if (dmaState.firstUsed) /* if this buffer is before any others */ 447 { /* jam at begining of list */ 448 lastDmaPtr = dmaState.firstUsed; 449 dmaState.firstUsed = dmaPtr; 450 dmaPtr->node.next = (ALLink*)lastDmaPtr; 451 dmaPtr->node.prev = 0; 452 lastDmaPtr->node.prev = (ALLink*)dmaPtr; 453 } 454 else /* no buffers in list, this is the first one */ 455 { 456 dmaState.firstUsed = dmaPtr; 457 dmaPtr->node.next = 0; 458 dmaPtr->node.prev = 0; 459 } 460 461 foundBuffer = dmaPtr->ptr; 462 delta = addr & 0x1; 463 addr -= delta; 464 dmaPtr->startAddr = addr; 465 dmaPtr->lastFrame = audFrameCt; /* mark it */ 466 467 osPiStartDma(&audDMAIOMesgBuf[nextDMA++], OS_MESG_PRI_HIGH, OS_READ, 468 (u32)addr, foundBuffer, wess_driver_dma_buffer_length, &audDMAMessageQ); 469 470 return (int)osVirtualToPhysical(foundBuffer) + delta; 471 } 472 473 ALDMAproc __amDmaNew(AMDMAState **state) // 8002EF48 474 { 475 476 if (!dmaState.initialized) /* only do this once */ 477 { 478 dmaState.firstUsed = 0; 479 dmaState.initialized = 1; 480 dmaState.firstFree = &dmaBuffs[0]; 481 } 482 483 return __amDMA; 484 } 485 486 void __clearAudioDMA(void) // 8002EF7C 487 { 488 u32 i; 489 OSIoMesg *iomsg; 490 AMDMABuffer *dmaPtr, *nextPtr; 491 492 /* Don't block here. If dma's aren't complete, you've had an audio */ 493 /* overrun. (Bad news, but go for it anyway, and try and recover. */ 494 for (i = 0; i<nextDMA; i++) 495 { 496 if (osRecvMesg(&audDMAMessageQ, (OSMesg *)&iomsg, OS_MESG_NOBLOCK) == -1) 497 { 498 wess_error_callback("DMANOTDONE", 0, 0); 499 } 500 } 501 502 dmaPtr = dmaState.firstUsed; 503 504 while (dmaPtr) 505 { 506 507 nextPtr = (AMDMABuffer*)dmaPtr->node.next; 508 509 /* remove old dma's from list */ 510 /* Can change FRAME_LAG value if we want. Should be at least one. */ 511 /* Larger values mean more buffers needed, but fewer DMA's */ 512 if (dmaPtr->lastFrame + wess_driver_frame_lag < audFrameCt) 513 { 514 if (dmaState.firstUsed == dmaPtr) 515 dmaState.firstUsed = (AMDMABuffer*)dmaPtr->node.next; 516 517 alUnlink((ALLink*)dmaPtr); 518 519 if (dmaState.firstFree) 520 { 521 alLink((ALLink*)dmaPtr, (ALLink*)dmaState.firstFree); 522 } 523 else 524 { 525 dmaState.firstFree = dmaPtr; 526 dmaPtr->node.next = 0; 527 dmaPtr->node.prev = 0; 528 } 529 } 530 531 dmaPtr = nextPtr; 532 } 533 534 nextDMA = 0; /* Reset number of DMAs */ 535 audFrameCt++; 536 } 537 538 void wess_exit(void) // 8002F0CC 539 { 540 wesssys_exit(YesRestore); 541 alClose(&__am.g); 542 } 543 544 #endif // 0