cog/Frameworks/lazyusf/lazyusf/audiolib.c

272 lines
6.7 KiB
C

#include "usf.h"
#include "usf_internal.h"
#include "cpu_hle.h"
#include "audiolib.h"
#include "os.h"
#include "main.h"
#include "memory.h"
#define N64WORD(x) (*(uint32_t*)PageVRAM((x)))
#define N64HALF(x) (*(uint16_t*)PageVRAM((x)))
#define N64BYTE(x) (*(uint8_t*)PageVRAM((x)))
int alCopy(usf_state_t * state, int paddr) {
uint32_t source = (state->GPR[4].UW[0]);
uint32_t dest = (state->GPR[5].UW[0]);
uint32_t len = (state->GPR[6].UW[0]);
if(len&3)
DisplayError(state, "OMG!!!! - alCopy length & 3\n");
memcpyn642n64(state, dest, source, len);
return 1;
}
int alLink(usf_state_t * state, int paddr) {
ALLink *element = (ALLink*)PageVRAM(state->GPR[4].UW[0]);
ALLink *after = (ALLink*)PageVRAM(state->GPR[5].UW[0]);
ALLink *afterNext;
element->next = after->next;
element->prev = state->GPR[5].UW[0];
if (after->next) {
afterNext = (ALLink*)PageVRAM(after->next);
afterNext->prev = state->GPR[4].UW[0];
}
after->next = state->GPR[4].UW[0];
return 1;
}
int alUnLink(usf_state_t * state, int paddr) {
ALLink *element = (ALLink*)PageVRAM(state->GPR[4].UW[0]);
ALLink *elementNext = (ALLink*)PageVRAM(element->next);
ALLink *elementPrev = (ALLink*)PageVRAM(element->prev);
// _asm int 3
if (element->next)
elementNext->prev = element->prev;
if (element->prev)
elementPrev->next = element->next;
return 1;
}
int alEvtqPostEvent(usf_state_t * state, int paddr) {
ALEventQueue *evtq;
ALEvent *events;
uint32_t A0 = state->GPR[4].UW[0];
uint32_t A1 = state->GPR[5].UW[0];
uint32_t DeltaTime = state->GPR[6].UW[0];
uint32_t nodeNext = 0;
uint32_t nextItem = 0;
uint32_t node = 0;
uint32_t nextDelta = 0;
uint32_t item = 0;
uint32_t postWhere = 0;
uint32_t NEXT = 0;
uint32_t nextItemDelta = 0;
evtq = (ALEventQueue *)PageVRAM(A0);
events = (ALEvent *)PageVRAM(A1);
//_asm int 3
NEXT = evtq->freeList.next;
if(NEXT == 0)
return 1;
//DisplayError("%08x", N64WORD(0x800533E4));
//cprintf("%08x\t%08x\n", N64WORD(0x800533D4), N64WORD(0x800533D8));
item = NEXT;
state->GPR[4].UW[0] = NEXT;
alUnLink(state, 0);
state->GPR[4].UW[0] = A1; state->GPR[5].UW[0] = NEXT + 0xC; state->GPR[6].UW[0] = 0x10;
alCopy(state, 0);
postWhere = (DeltaTime==0x7FFFFFFF)?1:0;
nodeNext = A0;
node = nodeNext + 8;
while(nodeNext !=0 ) {
nodeNext = *(uint32_t*)PageVRAM(node);
if(nodeNext != 0) {
nextDelta = *(uint32_t*)PageVRAM(nodeNext + 8);
nextItem = nodeNext;
if(DeltaTime < nextDelta) {
*(uint32_t*)PageVRAM(item + 8) = DeltaTime;
nextItemDelta = *(uint32_t*)PageVRAM(nextItem + 8);
*(uint32_t*)PageVRAM(nextItem + 8) = nextItemDelta - DeltaTime;
state->GPR[4].UW[0] = item; state->GPR[5].UW[0] = node;
alLink(state, 0);
return 1;
} else {
node = nodeNext;
DeltaTime -= nextDelta;
if(node == 0)
return 1;
}
}
}
if(postWhere == 0)
*(uint32_t*)PageVRAM(item + 8) = DeltaTime;
else
*(uint32_t*)PageVRAM(item + 8) = 0;
state->GPR[4].UW[0] = item; state->GPR[5].UW[0] = node;
alLink(state, 0);
return 1;
}
int alEvtqPostEvent_Alt(usf_state_t * state, int paddr) {
return 0;
}
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
uint32_t __nextSampleTime(usf_state_t * state, uint32_t driver, uint32_t *client) {
uint32_t c = 0;
int32_t deltaTime = 0x7FFFFFFF;
*client = 0;
for(c = N64WORD(driver); c != 0; c = N64WORD(c)) {
int samplesLeft = N64WORD(c + 0x10);
int curSamples = N64WORD(driver + 0x20);
if((samplesLeft - curSamples) < deltaTime) {
*client = c;
deltaTime = samplesLeft - curSamples;
}
}
return N64WORD((*client)+0x10);
}
int32_t _timeToSamplesNoRound(usf_state_t * state, long synth, long micros)
{
uint32_t outputRate = N64WORD(synth+0x44);
float tmp = ((float)micros) * outputRate / 1000000.0 + 0.5;
//DisplayError("Smaple rate is %d", outputRate);
return (int32_t)tmp;
}
uint32_t byteswap(char b[4] ) {
uint32_t out = 0;
out += b[3];
out += b[2] << 8;
out += b[1] << 16;
out += b[0] << 24;
return out;
}
int alAudioFrame(usf_state_t * state, int paddr) {
uint32_t alGlobals = 0;
uint32_t driver = 0, *paramSamples, *curSamples, client = 0, dl = 0;
uint32_t A0 = state->GPR[4].UW[0];
uint32_t A1 = state->GPR[5].UW[0];
uint32_t A2 = state->GPR[6].UW[0];
uint32_t outLen = state->GPR[7].UW[0];
uint32_t cmdlEnd = A0;
uint32_t lOutBuf = A2;
alGlobals = ((*(uint16_t*)PageRAM2(paddr + 0x8)) & 0xFFFF) << 16; //alGlobals->drvr
alGlobals += *(int16_t*)PageRAM2(paddr + 0xc);
//alGlobals = 0x80750C74;
driver = N64WORD(alGlobals);
paramSamples = (uint32_t*) PageVRAM(driver + 0x1c);
curSamples = (uint32_t*) PageVRAM(driver + 0x20);
if(N64WORD(driver) == 0) { // if(drvr->head == 0)
N64WORD(A1) = 0;
state->GPR[2].UW[0] = A0;
return 1;
}
for(*paramSamples = __nextSampleTime(state, driver, &client); (*paramSamples - *curSamples) < outLen; *paramSamples = __nextSampleTime(state, driver, &client)) {
int32_t *cSamplesLeft;
cSamplesLeft = (int32_t *) PageVRAM(client + 0x10);
*paramSamples &= ~0xf;
//run handler (not-HLE'd)
state->GPR[4].UW[0] = client;
RunFunction(state, N64WORD(client+0x8));
*cSamplesLeft += _timeToSamplesNoRound(state, driver, state->GPR[2].UW[0]);
}
*paramSamples &= ~0xf;
//give us some stack
state->GPR[0x1d].UW[0] -= 0x20;
N64WORD(state->GPR[0x1d].UW[0]+0x4) = 0; //tmp
while (outLen > 0) {
uint32_t maxOutSamples = 0, nOut = 0, cmdPtr = 0, output = 0, setParam = 0, handler = 0;
maxOutSamples = N64WORD(driver + 0x48);
nOut = MIN(maxOutSamples, outLen);
cmdPtr = cmdlEnd;//+8;
output = N64WORD(driver + 0x38);
setParam = N64WORD(output+8); // alSaveParam
state->GPR[4].DW = output;
state->GPR[5].DW = 0x6; // AL_FILTER_SET_DRAM
state->GPR[6].DW = lOutBuf;
RunFunction(state, setParam);
handler = N64WORD(output+4); // alSavePull
state->GPR[4].DW = output;
state->GPR[5].DW = state->GPR[0x1d].UW[0]+0x12; //&tmp
state->GPR[6].DW = nOut;
state->GPR[7].DW = *curSamples;
N64WORD(state->GPR[0x1d].UW[0]+0x10) = cmdPtr;
RunFunction(state, handler);
curSamples = (uint32_t *) PageVRAM(driver + 0x20);
cmdlEnd = state->GPR[2].UW[0];
outLen -= nOut;
lOutBuf += (nOut<<2);
*curSamples += nOut;
}
state->GPR[0x1d].UW[0] += 0x20;
N64WORD(A1) = (int32_t) ((cmdlEnd - A0) >> 3);
state->GPR[4].UW[0] = driver;
while( (dl = N64WORD(driver+0x14)) ) {
state->GPR[4].UW[0] = dl;
alUnLink(state, 0);
state->GPR[4].UW[0] = dl;
state->GPR[5].UW[0] = driver + 4;
alLink(state, 0);
}
state->GPR[2].UW[0] = cmdlEnd;
return 1;
}