More work on hardware.c

Former-commit-id: 033f8f5881
This commit is contained in:
Phillip Stephens 2023-02-18 23:41:18 -08:00
parent e0fb3afb11
commit b750480182
4 changed files with 409 additions and 23 deletions

View File

@ -107,6 +107,13 @@ void sndSilence();
#define SND_AUX_REASON_BUFFERUPDATE 0 #define SND_AUX_REASON_BUFFERUPDATE 0
#define SND_AUX_REASON_PARAMETERUPDATE 1 #define SND_AUX_REASON_PARAMETERUPDATE 1
typedef enum {
SND_STUDIO_TYPE_STD = 0,
SND_STUDIO_TYPE_RESERVED0 = 1,
SND_STUDIO_TYPE_RESERVED1 = 2,
SND_STUDIO_TYPE_RESERVED2 = 3,
} SND_STUDIO_TYPE;
typedef struct SND_AUX_INFO { typedef struct SND_AUX_INFO {
union SND_AUX_DATA { union SND_AUX_DATA {
struct SND_AUX_BUFFERUPDATE { struct SND_AUX_BUFFERUPDATE {
@ -173,6 +180,8 @@ typedef struct SND_AUX_DELAY {
u32 output[3]; // Output volume in % per channel u32 output[3]; // Output volume in % per channel
} SND_AUX_DELAY; } SND_AUX_DELAY;
typedef void (*SND_AUX_CALLBACK)(u8 reason, SND_AUX_INFO* info, void* user);
void sndAuxCallbackDelay(u8 reason, SND_AUX_INFO* info, void* user); void sndAuxCallbackDelay(u8 reason, SND_AUX_INFO* info, void* user);
bool sndAuxCallbackUpdateSettingsDelay(SND_AUX_DELAY* delay); bool sndAuxCallbackUpdateSettingsDelay(SND_AUX_DELAY* delay);
bool sndAuxCallbackPrepareDelay(SND_AUX_DELAY* rev); bool sndAuxCallbackPrepareDelay(SND_AUX_DELAY* rev);

View File

@ -105,7 +105,7 @@ typedef struct _PBDPOP {
unsigned short aAuxBS; // offset 0x10, size 0x2 unsigned short aAuxBS; // offset 0x10, size 0x2
} _PBDPOP; } _PBDPOP;
struct _PBVE { typedef struct _PBVE {
// total size: 0x4 // total size: 0x4
unsigned short currentVolume; // offset 0x0, size 0x2 unsigned short currentVolume; // offset 0x0, size 0x2
unsigned short currentDelta; // offset 0x2, size 0x2 unsigned short currentDelta; // offset 0x2, size 0x2
@ -139,7 +139,7 @@ typedef struct _PBADPCM {
unsigned short yn2; // offset 0x26, size 0x2 unsigned short yn2; // offset 0x26, size 0x2
} _PDADPCM; } _PDADPCM;
struct _PBSRC { typedef struct _PBSRC {
// total size: 0xE // total size: 0xE
unsigned short ratioHi; // offset 0x0, size 0x2 unsigned short ratioHi; // offset 0x0, size 0x2
unsigned short ratioLo; // offset 0x2, size 0x2 unsigned short ratioLo; // offset 0x2, size 0x2
@ -306,7 +306,7 @@ typedef struct CTRL_DEST {
u8 numSource; u8 numSource;
} CTRL_DEST; } CTRL_DEST;
struct SND_VIRTUALSAMPLE_INFO { typedef struct SND_VIRTUALSAMPLE_INFO {
// total size: 0x14 // total size: 0x14
unsigned short smpID; // offset 0x0, size 0x2 unsigned short smpID; // offset 0x0, size 0x2
unsigned short instID; // offset 0x2, size 0x2 unsigned short instID; // offset 0x2, size 0x2
@ -474,6 +474,95 @@ typedef struct SYNTH_VOICE {
u16 curOutputVolume; // offset 0x400, size 0x2 u16 curOutputVolume; // offset 0x400, size 0x2
} SYNTH_VOICE; } SYNTH_VOICE;
#pragma pop #pragma pop
typedef struct SAL_VOLINFO {
// total size: 0x24
float volL; // offset 0x0, size 0x4
float volR; // offset 0x4, size 0x4
float volS; // offset 0x8, size 0x4
float volAuxAL; // offset 0xC, size 0x4
float volAuxAR; // offset 0x10, size 0x4
float volAuxAS; // offset 0x14, size 0x4
float volAuxBL; // offset 0x18, size 0x4
float volAuxBR; // offset 0x1C, size 0x4
float volAuxBS; // offset 0x20, size 0x4
} SAL_VOLINFO;
typedef struct _SPB {
// total size: 0x36
unsigned short dpopLHi; // offset 0x0, size 0x2
unsigned short dpopLLo; // offset 0x2, size 0x2
unsigned short dpopLDelta; // offset 0x4, size 0x2
unsigned short dpopRHi; // offset 0x6, size 0x2
unsigned short dpopRLo; // offset 0x8, size 0x2
unsigned short dpopRDelta; // offset 0xA, size 0x2
unsigned short dpopSHi; // offset 0xC, size 0x2
unsigned short dpopSLo; // offset 0xE, size 0x2
unsigned short dpopSDelta; // offset 0x10, size 0x2
unsigned short dpopALHi; // offset 0x12, size 0x2
unsigned short dpopALLo; // offset 0x14, size 0x2
unsigned short dpopALDelta; // offset 0x16, size 0x2
unsigned short dpopARHi; // offset 0x18, size 0x2
unsigned short dpopARLo; // offset 0x1A, size 0x2
unsigned short dpopARDelta; // offset 0x1C, size 0x2
unsigned short dpopASHi; // offset 0x1E, size 0x2
unsigned short dpopASLo; // offset 0x20, size 0x2
unsigned short dpopASDelta; // offset 0x22, size 0x2
unsigned short dpopBLHi; // offset 0x24, size 0x2
unsigned short dpopBLLo; // offset 0x26, size 0x2
unsigned short dpopBLDelta; // offset 0x28, size 0x2
unsigned short dpopBRHi; // offset 0x2A, size 0x2
unsigned short dpopBRLo; // offset 0x2C, size 0x2
unsigned short dpopBRDelta; // offset 0x2E, size 0x2
unsigned short dpopBSHi; // offset 0x30, size 0x2
unsigned short dpopBSLo; // offset 0x32, size 0x2
unsigned short dpopBSDelta; // offset 0x34, size 0x2
} _SPB;
typedef struct DSPhostDPop {
// total size: 0x24
long l; // offset 0x0, size 0x4
long r; // offset 0x4, size 0x4
long s; // offset 0x8, size 0x4
long lA; // offset 0xC, size 0x4
long rA; // offset 0x10, size 0x4
long sA; // offset 0x14, size 0x4
long lB; // offset 0x18, size 0x4
long rB; // offset 0x1C, size 0x4
long sB; // offset 0x20, size 0x4
} DSPhostDPop;
typedef struct DSPinput {
// total size: 0xC
unsigned char studio; // offset 0x0, size 0x1
unsigned short vol; // offset 0x2, size 0x2
unsigned short volA; // offset 0x4, size 0x2
unsigned short volB; // offset 0x6, size 0x2
struct SND_STUDIO_INPUT* desc; // offset 0x8, size 0x4
} DSPinput;
typedef struct DSPstudioinfo {
// total size: 0xBC
struct _SPB* spb; // offset 0x0, size 0x4
struct DSPhostDPop hostDPopSum; // offset 0x4, size 0x24
long* main[2]; // offset 0x28, size 0x8
long* auxA[3]; // offset 0x30, size 0xC
long* auxB[3]; // offset 0x3C, size 0xC
struct DSPvoice* voiceRoot; // offset 0x48, size 0x4
struct DSPvoice* alienVoiceRoot; // offset 0x4C, size 0x4
unsigned char state; // offset 0x50, size 0x1
unsigned char isMaster; // offset 0x51, size 0x1
unsigned char numInputs; // offset 0x52, size 0x1
SND_STUDIO_TYPE type; // offset 0x54, size 0x4
struct DSPinput in[7]; // offset 0x58, size 0x54
SND_AUX_CALLBACK auxAHandler; // offset 0xAC, size 0x4
SND_AUX_CALLBACK auxBHandler; // offset 0xB0, size 0x4
void* auxAUser; // offset 0xB4, size 0x4
void* auxBUser; // offset 0xB8, size 0x4
} DSPstudioinfo;
extern DSPstudioinfo dspStudio[8];
extern SYNTH_VOICE* synthVoice; extern SYNTH_VOICE* synthVoice;
extern DSPvoice* dspVoice; extern DSPvoice* dspVoice;
@ -500,7 +589,7 @@ u8* sndBSearch(u16* key, u8* subTab, s32 mainTab, s32 len, SND_COMPARE cmp);
void sndConvertMs(u32* time); void sndConvertMs(u32* time);
void sndConvertTicks(u32* out, u32 seconds); void sndConvertTicks(u32* out, u32 seconds);
u32 sndConvert2Ms(u32 time); u32 sndConvert2Ms(u32 time);
void hwActivateStudio(u8 studio, u32 arg1, u32 arg2); void hwActivateStudio(unsigned char studio, unsigned long isMaster, SND_STUDIO_TYPE type);
void hwDeactivateStudio(u8); void hwDeactivateStudio(u8);
u32 hwIsActive(s32); u32 hwIsActive(s32);
@ -523,7 +612,12 @@ u32 salInitAi(SND_SOME_CALLBACK, u32, u32*);
u32 salInitDsp(u32); u32 salInitDsp(u32);
u32 salInitDspCtrl(u32, u32, u16); u32 salInitDspCtrl(u32, u32, u16);
u32 salStartAi(); u32 salStartAi();
void salActivateStudio(u8 studio, u32 isMaster, SND_STUDIO_TYPE type);
void salDeactivateStudio(unsigned char studio);
void salActivateVoice(DSPvoice* dsp_vptr, u8 studio);
void salCalcVolume(u8 voltab_index, SAL_VOLINFO* vi, float vol, u32 pan, u32 span, float auxa,
float auxb, u32 itd, u32 dpl2);
void salReconnectVoice(DSPvoice* dsp_vptr, u8 studio);
void* salMalloc(u32 len); void* salMalloc(u32 len);
void salFree(void* addr); void salFree(void* addr);
@ -546,12 +640,24 @@ typedef struct SND_STREAM_INFO {
void streamOutputModeChanged(); void streamOutputModeChanged();
/* TODO: Figure out what `unk` is */ /* TODO: Figure out what `unk` is */
bool hwAddInput(u8 studio, void* unk); void hwSetSRCType(u32 v, u8 salSRCType);
bool hwRemoveInput(u8 studio, void* unk); void hwSetITDMode(u32 v, u8 mode);
void hwSetPolyPhaseFilter(unsigned long v, unsigned char salCoefSel);
bool hwAddInput(u8 studio, SND_STUDIO_INPUT* in_desc);
bool hwRemoveInput(u8 studio, SND_STUDIO_INPUT* in_desc);
void hwChangeStudio(u32 v, u8 studio);
void hwDisableHRTF(); void hwDisableHRTF();
extern u32 dspCmdList; extern u32 dspCmdList;
extern u16 dspCmdFirstSize; extern u16 dspCmdFirstSize;
extern u8 dspScale2IndexTab[1024];
u32 aramGetStreamBufferAddress(unsigned char id, unsigned long* len);
void aramUploadData(void* mram, unsigned long aram, unsigned long len, unsigned long highPrio,
void (*callback)(unsigned long), unsigned long user);
void aramFreeStreamBuffer(u8 id);
void * aramStoreData(void * src, unsigned long len);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -6,8 +6,6 @@
extern "C" { extern "C" {
#endif #endif
typedef void (*SND_AUX_CALLBACK)(u8 reason, SND_AUX_INFO* info, void* user);
extern SND_AUX_CALLBACK synthAuxACallback[8]; extern SND_AUX_CALLBACK synthAuxACallback[8];
extern u8 synthAuxAMIDI[8]; extern u8 synthAuxAMIDI[8];
extern u8 synthAuxAMIDISet[8]; extern u8 synthAuxAMIDISet[8];

View File

@ -1,5 +1,14 @@
#include "musyx/musyx_priv.h" #include "musyx/musyx_priv.h"
static u16 itdOffTab[128] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8,
9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17,
17, 17, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 24, 25,
25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30,
31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
};
u8 salFrame; u8 salFrame;
u8 salAuxFrame; u8 salAuxFrame;
u8 salNumVoices; u8 salNumVoices;
@ -28,7 +37,7 @@ void snd_handle_irq() {
for (i = 0; i < salNumVoices; ++i) { for (i = 0; i < salNumVoices; ++i) {
for (j = 0; j < 5; ++j) { for (j = 0; j < 5; ++j) {
dspVoice[i].flags = 0; dspVoice[i].changed[j] = 0;
} }
} }
@ -104,7 +113,6 @@ void hwInitSamplePlayback(s32 v, u16 smpID, void* newsmp, u32 set_defadsr, u32 p
u32 callbackUserValue, u32 setSRC, u32 itdMode) { u32 callbackUserValue, u32 setSRC, u32 itdMode) {
unsigned char i; // r30 unsigned char i; // r30
unsigned long bf; // r29 unsigned long bf; // r29
DSPvoice* voice;
bf = 0; bf = 0;
for (i = 0; i <= salTimeOffset; ++i) { for (i = 0; i <= salTimeOffset; ++i) {
bf |= dspVoice[v].changed[i] & 0x20; bf |= dspVoice[v].changed[i] & 0x20;
@ -116,15 +124,7 @@ void hwInitSamplePlayback(s32 v, u16 smpID, void* newsmp, u32 set_defadsr, u32 p
dspVoice[v].mesgCallBackUserValue = callbackUserValue; dspVoice[v].mesgCallBackUserValue = callbackUserValue;
dspVoice[v].flags = 0; dspVoice[v].flags = 0;
dspVoice[v].smp_id = smpID; dspVoice[v].smp_id = smpID;
voice = &dspVoice[v]; dspVoice[v].smp_info = *(SAMPLE_INFO*)newsmp;
((u32*)&voice->smp_info)[0] = ((u32*)newsmp)[0];
((u32*)&voice->smp_info)[1] = ((u32*)newsmp)[1];
((u32*)&voice->smp_info)[2] = ((u32*)newsmp)[2];
((u32*)&voice->smp_info)[3] = ((u32*)newsmp)[3];
((u32*)&voice->smp_info)[4] = ((u32*)newsmp)[4];
((u32*)&voice->smp_info)[5] = ((u32*)newsmp)[5];
((u32*)&voice->smp_info)[6] = ((u32*)newsmp)[6];
((u32*)&voice->smp_info)[7] = ((u32*)newsmp)[7];
if (set_defadsr != 0) { if (set_defadsr != 0) {
dspVoice[v].adsr.mode = 0; dspVoice[v].adsr.mode = 0;
@ -152,9 +152,282 @@ void hwBreak(s32 vid) {
dspVoice[vid].startupBreak = 1; dspVoice[vid].startupBreak = 1;
} }
// dspVoice[vid].flags[salTimeOffset] |= 0x20; dspVoice[vid].changed[salTimeOffset] |= 0x20;
} }
void hwSetADSR(s32 vid, u32* param_2, u8 param_3) {} typedef struct ADSR_INFO {
// total size: 0x14
union ai_data {
struct {
// total size: 0x14
long atime; // offset 0x0, size 0x4
long dtime; // offset 0x4, size 0x4
unsigned short slevel; // offset 0x8, size 0x2
unsigned short rtime; // offset 0xA, size 0x2
long ascale; // offset 0xC, size 0x4
long dscale; // offset 0x10, size 0x4
} dls;
struct {
// total size: 0x8
unsigned short atime; // offset 0x0, size 0x2
unsigned short dtime; // offset 0x2, size 0x2
unsigned short slevel; // offset 0x4, size 0x2
unsigned short rtime; // offset 0x6, size 0x2
} linear;
} data; // offset 0x0, size 0x14
} ADSR_INFO;
void hwSetADSR(u32 v, void* _adsr, u8 mode) {
u32 sl; // r29
ADSR_INFO* adsr = (ADSR_INFO*)_adsr; // r30
switch (mode) {
case 0: {
dspVoice[v].adsr.mode = 0;
dspVoice[v].adsr.data.linear.aTime = adsr->data.linear.atime;
dspVoice[v].adsr.data.linear.dTime = adsr->data.linear.dtime;
sl = adsr->data.linear.slevel << 3;
if (sl > 0x7fff) {
sl = 0x7fff;
}
dspVoice[v].adsr.data.linear.sLevel = sl;
dspVoice[v].adsr.data.linear.rTime = adsr->data.linear.rtime;
break;
}
case 1:
case 2:
dspVoice[v].adsr.mode = 1;
dspVoice[v].adsr.data.dls.aMode = 0;
if (mode == 1) {
dspVoice[v].adsr.data.dls.aTime = adsrConvertTimeCents(adsr->data.dls.atime) & 0xFFFF;
dspVoice[v].adsr.data.dls.dTime = adsrConvertTimeCents(adsr->data.dls.dtime) & 0xFFFF;
sl = adsr->data.dls.slevel >> 2;
if (sl > 0x3ff) {
sl = 0x3ff;
}
dspVoice[v].adsr.data.dls.sLevel = 193 - dspScale2IndexTab[sl];
} else {
dspVoice[v].adsr.data.dls.aTime = adsr->data.dls.atime & 0xFFFF;
dspVoice[v].adsr.data.dls.dTime = adsr->data.dls.dtime & 0xFFFF;
dspVoice[v].adsr.data.dls.sLevel = adsr->data.dls.slevel;
}
dspVoice[v].adsr.data.dls.rTime = adsr->data.dls.rtime;
}
dspVoice[v].changed[0] |= 0x10;
}
void hwSetVirtualSampleLoopBuffer(u32 voice, void* addr, u32 len) {
dspVoice[voice].vSampleInfo.loopBufferAddr = addr;
dspVoice[voice].vSampleInfo.loopBufferLength = len;
}
u32 hwGetVirtualSampleState(u32 voice) { return dspVoice[voice].vSampleInfo.inLoopBuffer; }
u8 hwGetSampleType(u32 voice) { return dspVoice[voice].smp_info.compType; }
u16 hwGetSampleID(u32 voice) { return dspVoice[voice].smp_id; }
void hwSetStreamLoopPS(u32 voice, u8 ps) { dspVoice[voice].streamLoopPS = ps; }
void hwStart(u32 v, u8 studio) {
dspVoice[v].singleOffset = salTimeOffset;
salActivateVoice(&dspVoice[v], studio);
}
void hwKeyOff(u32 v) { dspVoice[v].changed[salTimeOffset] |= 0x40; }
void hwSetPitch(unsigned long v, unsigned short speed) {
struct DSPvoice* dsp_vptr = &dspVoice[v];
if (speed >= 0x4000) {
speed = 0x3fff;
}
if (dsp_vptr->lastUpdate.pitch != 0xff &&
dsp_vptr->pitch[dsp_vptr->lastUpdate.pitch] == speed * 16) {
return;
}
dsp_vptr->pitch[salTimeOffset] = speed * 16;
dsp_vptr->changed[salTimeOffset] |= 8;
dsp_vptr->lastUpdate.pitch = salTimeOffset;
}
void hwSetSRCType(u32 v, u8 salSRCType) {
static u16 dspSRCType[3] = {0, 1, 2};
struct DSPvoice* dsp_vptr = &dspVoice[v];
dsp_vptr->srcTypeSelect = dspSRCType[salSRCType];
dsp_vptr->changed[0] |= 0x100;
}
void hwSetPolyPhaseFilter(unsigned long v, unsigned char salCoefSel) {
static u16 dspCoefSel[3] = {0, 1, 2};
struct DSPvoice* dsp_vptr = &dspVoice[v];
dsp_vptr->srcCoefSelect = dspCoefSel[salCoefSel];
dsp_vptr->changed[0] |= 0x80;
}
void SetupITD(DSPvoice* dsp_vptr, u8 pan) {
dsp_vptr->itdShiftL = itdOffTab[pan];
dsp_vptr->itdShiftR = 32 - itdOffTab[pan];
dsp_vptr->changed[0] |= 0x200;
}
void hwSetITDMode(u32 v, u8 mode) {
if (!mode) {
dspVoice[v].flags |= 0x80000000;
dspVoice[v].itdShiftL = 16;
dspVoice[v].itdShiftR = 16;
return;
}
dspVoice[v].flags &= ~0x80000000;
}
void hwSetVolume(unsigned long v, unsigned char table, float vol, unsigned long pan,
unsigned long span, float auxa, float auxb) {
struct SAL_VOLINFO vi; // r1+0x24
unsigned short il; // r30
unsigned short ir; // r29
unsigned short is; // r28
DSPvoice* dsp_vptr = &dspVoice[v]; // r31
if (vol >= 1.f) {
vol = 1.f;
}
if (auxa >= 1.f) {
auxa = 1.f;
}
if (auxb >= 1.f) {
auxb = 1.f;
}
salCalcVolume(table, &vi, vol, pan, span, auxa, auxb, (dsp_vptr->flags & 0x80000000) != 0,
dspStudio[dsp_vptr->studio].type == SND_STUDIO_TYPE_RESERVED0);
il = 32767.f * vi.volL;
ir = 32767.f * vi.volR;
is = 32767.f * vi.volS;
if (dsp_vptr->lastUpdate.vol == 0xff || dsp_vptr->volL != il || dsp_vptr->volR != ir ||
dsp_vptr->volS != is) {
dsp_vptr->volL = il;
dsp_vptr->volR = ir;
dsp_vptr->volS = is;
dsp_vptr->changed[0] |= 1;
dsp_vptr->lastUpdate.vol = 0;
}
il = 32767.f * vi.volAuxAL;
ir = 32767.f * vi.volAuxAR;
is = 32767.f * vi.volAuxAS;
if (dsp_vptr->lastUpdate.volA == 0xff | dsp_vptr->volLa != il || dsp_vptr->volRa != ir ||
dsp_vptr->volSa != is) {
dsp_vptr->volLa = il;
dsp_vptr->volRa = ir;
dsp_vptr->volSa = is;
dsp_vptr->changed[0] |= 2;
dsp_vptr->lastUpdate.volA = 0;
}
il = 32767.f * vi.volAuxBL;
ir = 32767.f * vi.volAuxBR;
is = 32767.f * vi.volAuxBS;
if (dsp_vptr->lastUpdate.volB == 0xff || dsp_vptr->volLb != il || dsp_vptr->volRb != ir ||
dsp_vptr->volSb != is) {
dsp_vptr->volLb = il;
dsp_vptr->volRb = ir;
dsp_vptr->volSb = is;
dsp_vptr->changed[0] |= 4;
dsp_vptr->lastUpdate.volB = 0;
}
if (dsp_vptr->flags & 0x80000000) {
SetupITD(dsp_vptr, pan >> 16);
}
}
void hwOff(s32 vid) { salDeactivateVoice(&dspVoice[vid]); } void hwOff(s32 vid) { salDeactivateVoice(&dspVoice[vid]); }
void hwSetAUXProcessingCallbacks(u8 studio, SND_AUX_CALLBACK auxA, void* userA,
SND_AUX_CALLBACK auxB, void* userB) {
dspStudio[studio].auxAHandler = auxA;
dspStudio[studio].auxAUser = userA;
dspStudio[studio].auxBHandler = auxB;
dspStudio[studio].auxBUser = userB;
}
void hwActivateStudio(unsigned char studio, unsigned long isMaster, SND_STUDIO_TYPE type) {
salActivateStudio(studio, isMaster, type);
}
void hwDeactivateStudio(u8 studio) { salDeactivateStudio(studio); }
void hwChangeStudioMix(u8 studio, u32 isMaster) { dspStudio[studio].isMaster = isMaster; }
bool hwIsStudioActive(u32 studio) { return dspStudio[studio].state == 1; }
bool hwAddInput(u8 studio, SND_STUDIO_INPUT* in_desc) {
return salAddStudioInput(&dspStudio[studio], in_desc);
}
bool hwRemoveInput(u8 studio, SND_STUDIO_INPUT* in_desc) {
return salRemoveStudioInput(&dspStudio[studio], in_desc);
}
void hwChangeStudio(u32 v, u8 studio) { salReconnectVoice(&dspVoice[v], studio); }
u32 hwGetPos(unsigned long v) {}
void hwFlushStream(void* base, unsigned long offset, unsigned long bytes,
unsigned char hwStreamHandle, void (*callback)(unsigned long),
unsigned long user) {
unsigned long mram; // r29
unsigned long aram; // r28
unsigned long len;
aram = aramGetStreamBufferAddress(hwStreamHandle, &len);
bytes += ((offset & 31) + 31) & ~31;
mram = (u32)base + (offset & ~31);
DCStoreRange((void*)mram, len);
aramUploadData((void*)mram, aram + (offset & ~31), bytes, 1, callback, user);
}
u32 hwInitStream(u32 len) { return aramAllocateStreamBuffer(len); }
void hwExitStream(u8 id) { aramFreeStreamBuffer(id); }
void* hwGetStreamPlayBuffer(u8 hwStreamHandle) {
return (void*)aramGetStreamBufferAddress(hwStreamHandle, NULL);
}
void* hwTransAddr(void* samples) { return samples; }
u32 hwFrq2Pitch(u32 frq) { return (frq * 4096.f) / synthInfo.mixFrq; }
void hwInitSampleMem(u32 baseAddr, u32 length) { aramInit(length); }
void hwExitSampleMem() { aramExit(); }
u32 convert_length(u32 len, u8 type) {
switch (type) {
case 0:
return ((len + 13) / 14) * 8;
case 2:
return len * 2;
case 3:
return len;
default:
return len;
}
}
void hwSaveSample(void* header, void* data) {
//convert_length
}