DOOM64-RE

DOOM 64 Reverse Engineering
Log | Files | Refs | README | LICENSE

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