2020-03-31 18:55:57 +02:00
|
|
|
#include "LIBSPU.H"
|
|
|
|
#include "LIBETC.H"
|
|
|
|
#include <stdio.h>
|
2020-04-08 20:07:11 +02:00
|
|
|
|
2020-03-31 18:55:57 +02:00
|
|
|
#include "EMULATOR.H"
|
|
|
|
#include "LIBAPI.H"
|
2020-04-26 08:34:51 +02:00
|
|
|
#include "LIBMATH.H"
|
2020-03-31 18:55:57 +02:00
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
2020-03-31 19:09:22 +02:00
|
|
|
#define SPU_CENTERNOTE (-32768 / 2)
|
2020-03-31 18:55:57 +02:00
|
|
|
|
|
|
|
short _spu_voice_centerNote[24] =
|
|
|
|
{
|
|
|
|
SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE,
|
|
|
|
SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE,
|
|
|
|
SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE, SPU_CENTERNOTE
|
|
|
|
};
|
|
|
|
|
|
|
|
SpuCommonAttr dword_424;//Might be wrong struct, need to check
|
|
|
|
int _spu_isCalled = 0;
|
|
|
|
int _spu_FiDMA = 0;///@TODO decl as extern find initial value
|
|
|
|
int _spu_EVdma = 0;
|
|
|
|
int _spu_rev_flag = 0;
|
|
|
|
int _spu_rev_reserve_wa = 0;
|
|
|
|
int _spu_rev_offsetaddr = 0;
|
|
|
|
int _spu_rev_startaddr = 0;
|
|
|
|
int _spu_AllocBlockNum = 0;
|
|
|
|
int _spu_AllocLastNum = 0;
|
|
|
|
int _spu_memList = 0;
|
|
|
|
int _spu_trans_mode = 0;
|
|
|
|
int _spu_transMode = 0;
|
|
|
|
int _spu_keystat = 0;
|
|
|
|
int _spu_RQmask = 0;
|
|
|
|
int _spu_RQvoice = 0;
|
|
|
|
int _spu_env = 0;
|
|
|
|
char spu[440];//0x1F801C00 is base address
|
|
|
|
short* _spu_RXX = (short*)&spu[0];
|
|
|
|
int _spu_mem_mode_plus = 3;
|
|
|
|
void* _spu_transferCallback = NULL;///@TODO initial value check
|
|
|
|
int _spu_inTransfer = 0;///@TODO initial value check
|
|
|
|
unsigned short _spu_tsa = 0;
|
|
|
|
|
|
|
|
void _spu_t(int mode, int flag)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void _spu_Fw(unsigned char* addr, unsigned long size)
|
|
|
|
{
|
|
|
|
//v0 = _spu_transMode
|
|
|
|
//s1 = addr
|
|
|
|
//s0 = size
|
|
|
|
|
|
|
|
if (_spu_trans_mode == 0)
|
|
|
|
{
|
|
|
|
//v0 = _spu_tsa
|
|
|
|
//a1 = _spu_mem_mode_plus
|
|
|
|
//a0 = 2
|
|
|
|
_spu_t(2, _spu_tsa << _spu_mem_mode_plus);
|
|
|
|
///@TODO check if a1 is modified in spu_t
|
|
|
|
}
|
|
|
|
//loc_A84
|
|
|
|
#if 0
|
|
|
|
jal _spu_t
|
|
|
|
sllv $a1, $v0, $a1
|
|
|
|
|
|
|
|
jal _spu_t
|
|
|
|
li $a0, 1
|
|
|
|
|
|
|
|
li $a0, 3
|
|
|
|
move $a1, $s1
|
|
|
|
jal _spu_t
|
|
|
|
move $a2, $s0
|
|
|
|
j loc_A94
|
|
|
|
move $v0, $s0
|
|
|
|
|
|
|
|
loc_A84:
|
|
|
|
move $a0, $s1
|
|
|
|
jal sub_480
|
|
|
|
move $a1, $s0
|
|
|
|
move $v0, $s0
|
|
|
|
|
|
|
|
loc_A94:
|
|
|
|
lw $ra, 0x20+var_8($sp)
|
|
|
|
lw $s1, 0x20+var_C($sp)
|
|
|
|
lw $s0, 0x20+var_10($sp)
|
|
|
|
jr $ra
|
|
|
|
addiu $sp, 0x20
|
|
|
|
# End of function _spu_Fw
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-04-08 20:07:11 +02:00
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include <AL/al.h>
|
|
|
|
#include <AL/alc.h>
|
2020-04-09 15:55:21 +02:00
|
|
|
#include <AL/alext.h>
|
2020-04-08 20:07:11 +02:00
|
|
|
|
|
|
|
const char* getALCErrorString(int err)
|
|
|
|
{
|
|
|
|
switch (err)
|
|
|
|
{
|
|
|
|
case ALC_NO_ERROR:
|
|
|
|
return "AL_NO_ERROR";
|
|
|
|
case ALC_INVALID_DEVICE:
|
|
|
|
return "ALC_INVALID_DEVICE";
|
|
|
|
case ALC_INVALID_CONTEXT:
|
|
|
|
return "ALC_INVALID_CONTEXT";
|
|
|
|
case ALC_INVALID_ENUM:
|
|
|
|
return "ALC_INVALID_ENUM";
|
|
|
|
case ALC_INVALID_VALUE:
|
|
|
|
return "ALC_INVALID_VALUE";
|
|
|
|
case ALC_OUT_OF_MEMORY:
|
|
|
|
return "ALC_OUT_OF_MEMORY";
|
|
|
|
default:
|
|
|
|
return "AL_UNKNOWN";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* getALErrorString(int err)
|
|
|
|
{
|
|
|
|
switch (err)
|
|
|
|
{
|
|
|
|
case AL_NO_ERROR:
|
|
|
|
return "AL_NO_ERROR";
|
|
|
|
case AL_INVALID_NAME:
|
|
|
|
return "AL_INVALID_NAME";
|
|
|
|
case AL_INVALID_ENUM:
|
|
|
|
return "AL_INVALID_ENUM";
|
|
|
|
case AL_INVALID_VALUE:
|
|
|
|
return "AL_INVALID_VALUE";
|
|
|
|
case AL_INVALID_OPERATION:
|
|
|
|
return "AL_INVALID_OPERATION";
|
|
|
|
case AL_OUT_OF_MEMORY:
|
|
|
|
return "AL_OUT_OF_MEMORY";
|
|
|
|
default:
|
|
|
|
return "AL_UNKNOWN";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SPU_MEMSIZE (512 * 1024) // FIXME: isn't it very little?
|
|
|
|
#define SPU_VOICES 24
|
|
|
|
|
|
|
|
struct SPUMemory
|
|
|
|
{
|
|
|
|
unsigned char samplemem[SPU_MEMSIZE];
|
|
|
|
unsigned char* writeptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
static SPUMemory s_SpuMemory;
|
|
|
|
|
|
|
|
struct SPUVoice
|
|
|
|
{
|
|
|
|
SpuVoiceAttr attr; // .voice is Id of this channel
|
|
|
|
|
|
|
|
ALuint alBuffer;
|
|
|
|
ALuint alSource;
|
|
|
|
};
|
|
|
|
|
|
|
|
static SPUVoice s_SpuVoices[SPU_VOICES];
|
|
|
|
|
|
|
|
static ALCdevice* s_ALCdevice = NULL;
|
|
|
|
static ALCcontext* s_ALCcontext = NULL;
|
|
|
|
|
|
|
|
bool Emulator_InitSound()
|
|
|
|
{
|
|
|
|
if (s_ALCdevice)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
printf(" \n--------- InitOpenAL --------- \n");
|
|
|
|
|
|
|
|
// Init openAL
|
|
|
|
// check devices list
|
|
|
|
char* devices = (char*)alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
|
|
|
|
|
|
|
|
// go through device list (each device terminated with a single NULL, list terminated with double NULL)
|
|
|
|
while ((*devices) != '\0')
|
|
|
|
{
|
|
|
|
printf("found sound device: %s\n", devices);
|
|
|
|
devices += strlen(devices) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
s_ALCdevice = alcOpenDevice(NULL);
|
|
|
|
|
|
|
|
int alErr = AL_NO_ERROR;
|
|
|
|
|
|
|
|
if (!s_ALCdevice)
|
|
|
|
{
|
|
|
|
alErr = alcGetError(nullptr);
|
|
|
|
printf("alcOpenDevice: NULL DEVICE error: %s\n", getALCErrorString(alErr));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// out_channel_formats snd_outputchannels
|
|
|
|
int al_context_params[] =
|
|
|
|
{
|
|
|
|
ALC_FREQUENCY, 44100,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
s_ALCcontext = alcCreateContext(s_ALCdevice, al_context_params);
|
|
|
|
|
|
|
|
alErr = alcGetError(s_ALCdevice);
|
|
|
|
if (alErr != AL_NO_ERROR)
|
|
|
|
{
|
|
|
|
printf("alcCreateContext error: %s\n", getALCErrorString(alErr));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
alcMakeContextCurrent(s_ALCcontext);
|
|
|
|
|
|
|
|
alErr = alcGetError(s_ALCdevice);
|
|
|
|
if (alErr != AL_NO_ERROR)
|
|
|
|
{
|
|
|
|
printf("alcMakeContextCurrent error: %s\n", getALCErrorString(alErr));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup defaults
|
|
|
|
alListenerf(AL_GAIN, 1.0f);
|
2020-04-26 08:34:51 +02:00
|
|
|
alDistanceModel(AL_NONE);
|
2020-04-08 20:07:11 +02:00
|
|
|
|
|
|
|
// create channels
|
|
|
|
for (int i = 0; i < SPU_VOICES; i++)
|
|
|
|
{
|
|
|
|
SPUVoice& voice = s_SpuVoices[i];
|
2020-04-09 15:55:21 +02:00
|
|
|
memset(&voice, 0, sizeof(SPUVoice));
|
2020-04-08 20:07:11 +02:00
|
|
|
|
|
|
|
alGenSources(1, &voice.alSource);
|
|
|
|
alGenBuffers(1, &voice.alBuffer);
|
|
|
|
|
|
|
|
alSourcei(voice.alSource, AL_LOOPING, AL_FALSE);
|
|
|
|
alSourcei(voice.alSource, AL_SOURCE_RELATIVE, AL_TRUE);
|
|
|
|
alSourcef(voice.alSource, AL_MAX_GAIN, 1.0f);
|
|
|
|
alSourcef(voice.alSource, AL_DOPPLER_FACTOR, 1.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
// PSX ADPCM coefficients
|
|
|
|
const double K0[5] = { 0, 0.9375, 1.796875, 1.53125, 1.90625 };
|
|
|
|
const double K1[5] = { 0, 0, -0.8125, -0.859375, -0.9375 };
|
|
|
|
|
|
|
|
// PSX ADPCM decoding routine - decodes a single sample
|
|
|
|
short vagToPcm(unsigned char soundParameter, int soundData, double* vagPrev1, double* vagPrev2)
|
|
|
|
{
|
|
|
|
int resultInt = 0;
|
|
|
|
|
|
|
|
double dTmp1 = 0.0;
|
|
|
|
double dTmp2 = 0.0;
|
|
|
|
double dTmp3 = 0.0;
|
|
|
|
|
|
|
|
if (soundData > 7)
|
|
|
|
soundData -= 16;
|
|
|
|
|
|
|
|
dTmp1 = (double)soundData * pow(2, (double)(12 - (soundParameter & 0x0F)));
|
|
|
|
|
|
|
|
dTmp2 = (*vagPrev1) * K0[(soundParameter >> 4) & 0x0F];
|
|
|
|
dTmp3 = (*vagPrev2) * K1[(soundParameter >> 4) & 0x0F];
|
|
|
|
|
|
|
|
(*vagPrev2) = (*vagPrev1);
|
|
|
|
(*vagPrev1) = dTmp1 + dTmp2 + dTmp3;
|
|
|
|
|
|
|
|
resultInt = (int)round((*vagPrev1));
|
|
|
|
|
|
|
|
if (resultInt > 32767)
|
|
|
|
resultInt = 32767;
|
|
|
|
|
|
|
|
if (resultInt < -32768)
|
|
|
|
resultInt = -32768;
|
|
|
|
|
|
|
|
return (short)resultInt;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Main decoding routine - Takes PSX ADPCM formatted audio data and converts it to PCM. It also extracts the looping information if used.
|
|
|
|
int decodeSound(unsigned char* iData, short* oData, int soundSize, int* loopStart, int* loopLength, bool breakOnEnd = false)
|
|
|
|
{
|
|
|
|
unsigned char sp = 0;
|
|
|
|
int sd = 0;
|
|
|
|
double vagPrev1 = 0.0;
|
|
|
|
double vagPrev2 = 0.0;
|
|
|
|
int k = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < soundSize; i++)
|
|
|
|
{
|
|
|
|
if (i % 16 == 0)
|
|
|
|
{
|
|
|
|
sp = iData[i];
|
|
|
|
|
|
|
|
if (breakOnEnd && (iData[i + 1] & 0x0F) == 1)
|
|
|
|
return k;
|
|
|
|
|
|
|
|
if ((iData[i + 1] & 0x0E) == 6)
|
|
|
|
(*loopStart) = k;
|
|
|
|
|
|
|
|
if ((iData[i + 1] & 0x0F) == 3)
|
|
|
|
(*loopLength) = (k + 28) - (*loopStart);
|
|
|
|
|
|
|
|
if ((iData[i + 1] & 0x0F) == 7)
|
|
|
|
(*loopLength) = (k + 28) - (*loopStart);
|
|
|
|
|
|
|
|
i += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
sd = (int)iData[i] & 0x0F;
|
|
|
|
oData[k++] = vagToPcm(sp, sd, &vagPrev1, &vagPrev2);
|
|
|
|
sd = ((int)iData[i] >> 4) & 0x0F;
|
|
|
|
oData[k++] = vagToPcm(sp, sd, &vagPrev1, &vagPrev2);
|
|
|
|
}
|
|
|
|
|
|
|
|
return soundSize;
|
|
|
|
}
|
|
|
|
|
2020-03-31 18:55:57 +02:00
|
|
|
unsigned long SpuWrite(unsigned char* addr, unsigned long size)
|
|
|
|
{
|
|
|
|
if (0x7EFF0 < size)
|
|
|
|
{
|
|
|
|
size = 0x7EFF0;
|
|
|
|
}
|
|
|
|
|
2020-04-08 20:07:11 +02:00
|
|
|
// simply copy to the writeptr
|
|
|
|
memcpy(s_SpuMemory.writeptr, addr, size);
|
|
|
|
|
2020-03-31 18:55:57 +02:00
|
|
|
//loc_228
|
|
|
|
_spu_Fw(addr, size);
|
|
|
|
|
2020-04-08 20:07:11 +02:00
|
|
|
|
2020-03-31 18:55:57 +02:00
|
|
|
if (_spu_transferCallback == NULL)
|
|
|
|
{
|
|
|
|
_spu_inTransfer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
long SpuSetTransferMode(long mode)
|
|
|
|
{
|
2020-04-08 20:07:11 +02:00
|
|
|
// TODO: handle different transfer modes
|
|
|
|
|
2020-03-31 18:55:57 +02:00
|
|
|
long mode_fix = mode == 0 ? 0 : 1;
|
|
|
|
|
|
|
|
//trans_mode = mode;
|
|
|
|
//transMode = mode_fix;
|
|
|
|
|
|
|
|
return mode_fix;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long SpuSetTransferStartAddr(unsigned long addr)
|
|
|
|
{
|
2020-04-08 20:07:11 +02:00
|
|
|
s_SpuMemory.writeptr = s_SpuMemory.samplemem + addr;
|
2020-03-31 18:55:57 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
long SpuIsTransferCompleted(long flag)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _SpuDataCallback(int a0)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpuStart()//(F)
|
|
|
|
{
|
|
|
|
long event = 0;
|
|
|
|
|
|
|
|
if (_spu_isCalled == 0)
|
|
|
|
{
|
|
|
|
_spu_isCalled = 1;
|
|
|
|
EnterCriticalSection();
|
|
|
|
_SpuDataCallback(_spu_FiDMA);
|
2020-03-31 19:09:22 +02:00
|
|
|
//event = OpenEvent(HwSPU, EvSpCOMP, EvMdNOINTR, NULL);
|
2020-03-31 18:55:57 +02:00
|
|
|
_spu_EVdma = event;
|
|
|
|
EnableEvent(event);
|
|
|
|
ExitCriticalSection();
|
|
|
|
}
|
|
|
|
//loc_348
|
|
|
|
}
|
|
|
|
|
|
|
|
void _spu_init(int a0)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void _spu_FsetRXX(int a0, int a1, int a2)//(F)
|
|
|
|
{
|
|
|
|
if (a2 == 0)
|
|
|
|
{
|
|
|
|
_spu_RXX[a0] = a1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_spu_RXX[a0] = a1 >> _spu_mem_mode_plus;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _SpuInit(int a0)
|
|
|
|
{
|
|
|
|
ResetCallback();
|
|
|
|
_spu_init(a0);
|
|
|
|
|
|
|
|
if (a0 == 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < sizeof(_spu_voice_centerNote) / sizeof(short); i++)
|
|
|
|
{
|
|
|
|
_spu_voice_centerNote[i] = SPU_CENTERNOTE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//loc_240
|
|
|
|
SpuStart();
|
|
|
|
|
|
|
|
_spu_rev_flag = 0;
|
|
|
|
_spu_rev_reserve_wa = 0;
|
|
|
|
dword_424.mask = 0;
|
|
|
|
dword_424.mvol.left = 0;
|
|
|
|
dword_424.mvol.right = 0;
|
|
|
|
dword_424.mvolmode.left = 0;
|
|
|
|
dword_424.mvolmode.right = 0;
|
|
|
|
dword_424.mvolx.left = 0;
|
|
|
|
dword_424.mvolx.right = 0;
|
|
|
|
_spu_rev_offsetaddr = _spu_rev_startaddr;
|
|
|
|
_spu_FsetRXX(209, _spu_rev_startaddr, 0);
|
|
|
|
_spu_AllocBlockNum = 0;
|
|
|
|
_spu_AllocLastNum = 0;
|
|
|
|
_spu_memList = 0;
|
|
|
|
_spu_trans_mode = 0;
|
|
|
|
_spu_transMode = 0;
|
|
|
|
_spu_keystat = 0;
|
|
|
|
_spu_RQmask = 0;
|
|
|
|
_spu_RQvoice = 0;
|
|
|
|
_spu_env = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpuInit(void)
|
|
|
|
{
|
2020-04-08 20:07:11 +02:00
|
|
|
Emulator_InitSound();
|
|
|
|
|
2020-03-31 18:55:57 +02:00
|
|
|
_SpuInit(0);
|
|
|
|
}
|
|
|
|
|
2020-04-08 16:46:06 +02:00
|
|
|
void SpuSetVoiceAttr(SpuVoiceAttr *arg)
|
|
|
|
{
|
2020-04-08 20:07:11 +02:00
|
|
|
static short waveBuffer[SPU_MEMSIZE];
|
|
|
|
|
2020-04-12 17:35:24 +02:00
|
|
|
for (int i = 0; i < SPU_VOICES; i++)
|
|
|
|
{
|
|
|
|
if (arg->voice != SPU_VOICECH(i))
|
|
|
|
continue;
|
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
SPUVoice& voice = s_SpuVoices[i];
|
2020-04-12 17:35:24 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
// update sample
|
|
|
|
if ((arg->mask & SPU_VOICE_WDSA) || (arg->mask & SPU_VOICE_LSAX))
|
|
|
|
{
|
|
|
|
// welp
|
|
|
|
alSourceStop(voice.alSource);
|
|
|
|
alSourcei(voice.alSource, AL_BUFFER, 0);
|
2020-04-12 17:35:24 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
if (arg->mask & SPU_VOICE_WDSA)
|
|
|
|
voice.attr.addr = arg->addr;
|
2020-04-08 20:07:11 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
if (arg->mask & SPU_VOICE_LSAX)
|
|
|
|
voice.attr.loop_addr = arg->loop_addr;
|
2020-04-08 20:07:11 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
char flag = s_SpuMemory.samplemem[voice.attr.addr * 8 + 1];
|
2020-04-09 15:55:21 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
int loopStart = 0, loopLen = 0;
|
|
|
|
int count = decodeSound(s_SpuMemory.samplemem + voice.attr.addr, waveBuffer, SPU_MEMSIZE - voice.attr.addr, &loopStart, &loopLen, true);
|
2020-04-09 15:55:21 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
if (loopLen > 0)
|
|
|
|
{
|
|
|
|
loopStart += voice.attr.loop_addr;
|
2020-04-08 20:07:11 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
int sampleOffs[] = { loopStart, loopStart + loopLen };
|
|
|
|
alBufferiv(voice.alBuffer, AL_LOOP_POINTS_SOFT, sampleOffs);
|
|
|
|
}
|
2020-04-09 15:55:21 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
alBufferData(voice.alBuffer, AL_FORMAT_MONO16, waveBuffer, count * sizeof(short), 350000);
|
2020-04-09 15:55:21 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
// set the buffer
|
|
|
|
alSourcei(voice.alSource, AL_BUFFER, voice.alBuffer);
|
|
|
|
alSourcei(voice.alSource, AL_SAMPLE_OFFSET, 0);
|
2020-04-09 15:55:21 +02:00
|
|
|
}
|
2020-04-08 20:07:11 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
// update volume
|
|
|
|
if ((arg->mask & SPU_VOICE_VOLL) || (arg->mask & SPU_VOICE_VOLR))
|
|
|
|
{
|
|
|
|
if (arg->mask & SPU_VOICE_VOLL)
|
|
|
|
voice.attr.volume.left = arg->volume.left;
|
2020-04-08 20:07:11 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
if (arg->mask & SPU_VOICE_VOLR)
|
|
|
|
voice.attr.volume.right = arg->volume.right;
|
2020-04-08 20:07:11 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
float left_gain = float(voice.attr.volume.left) / float(16384);
|
|
|
|
float right_gain = float(voice.attr.volume.right) / float(16384);
|
2020-04-09 15:55:21 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
float pan = (acosf(left_gain) + asinf(right_gain)) / ((float)M_PI); // average angle in [0,1]
|
|
|
|
pan = 2 * pan - 1; // convert to [-1, 1]
|
|
|
|
pan = pan * 0.5f; // 0.5 = sin(30') for a +/- 30 degree arc
|
|
|
|
alSource3f(voice.alSource, AL_POSITION, pan, 0, -sqrtf(1.0f - pan * pan));
|
2020-04-08 20:07:11 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
//alSourcef(voice.alSource, AL_GAIN, 1.0f);
|
|
|
|
}
|
2020-04-09 15:55:21 +02:00
|
|
|
|
2020-04-26 08:34:51 +02:00
|
|
|
// update pitch
|
|
|
|
if (arg->mask & SPU_VOICE_PITCH)
|
|
|
|
{
|
|
|
|
voice.attr.pitch = arg->pitch;
|
|
|
|
alSourcef(voice.alSource, AL_PITCH, float(voice.attr.pitch) / 32767.0f);
|
|
|
|
}
|
2020-04-09 15:55:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpuSetKey(long on_off, unsigned long voice_bit)
|
|
|
|
{
|
2020-04-12 16:33:55 +02:00
|
|
|
for (int i = 0; i < SPU_VOICES; i++)
|
|
|
|
{
|
|
|
|
if (voice_bit != SPU_VOICECH(i))
|
|
|
|
continue;
|
2020-04-09 15:55:21 +02:00
|
|
|
|
2020-04-12 16:33:55 +02:00
|
|
|
SPUVoice& voice = s_SpuVoices[i];
|
2020-04-09 15:55:21 +02:00
|
|
|
|
2020-04-12 16:33:55 +02:00
|
|
|
//int state;
|
|
|
|
//alGetSourcei(voice.alSource, AL_SOURCE_STATE, &state);
|
2020-04-08 20:07:11 +02:00
|
|
|
|
2020-04-12 16:33:55 +02:00
|
|
|
if (on_off)
|
|
|
|
{
|
|
|
|
// stop, rewind, start
|
|
|
|
alSourceStop(voice.alSource);
|
|
|
|
alSourceRewind(voice.alSource);
|
|
|
|
|
|
|
|
alSourcePlay(voice.alSource);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
alSourceStop(voice.alSource);
|
|
|
|
}
|
2020-04-08 20:07:11 +02:00
|
|
|
}
|
2020-04-08 16:46:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
long SpuGetKeyStatus(unsigned long voice_bit)
|
|
|
|
{
|
2020-04-12 16:33:55 +02:00
|
|
|
int state = AL_STOPPED;
|
2020-04-08 20:07:11 +02:00
|
|
|
|
2020-04-12 16:33:55 +02:00
|
|
|
for (int i = 0; i < SPU_VOICES; i++)
|
|
|
|
{
|
|
|
|
if (voice_bit != SPU_VOICECH(i))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SPUVoice& voice = s_SpuVoices[i];
|
|
|
|
|
|
|
|
alGetSourcei(voice.alSource, AL_SOURCE_STATE, &state);
|
|
|
|
break;
|
|
|
|
}
|
2020-04-08 20:07:11 +02:00
|
|
|
|
|
|
|
return (state == AL_PLAYING); // simple as this?
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpuGetAllKeysStatus(char* status)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < SPU_VOICES; i++)
|
|
|
|
{
|
|
|
|
SPUVoice& voice = s_SpuVoices[i];
|
|
|
|
|
|
|
|
int state;
|
|
|
|
alGetSourcei(voice.alSource, AL_SOURCE_STATE, &state);
|
|
|
|
|
|
|
|
status[i] = (state == AL_PLAYING);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpuSetKeyOnWithAttr(SpuVoiceAttr* attr)
|
|
|
|
{
|
|
|
|
SpuSetVoiceAttr(attr);
|
|
|
|
SpuSetKey(1, attr->voice);
|
2020-04-08 16:46:06 +02:00
|
|
|
}
|
|
|
|
|
2020-03-31 19:00:33 +02:00
|
|
|
long SpuSetMute(long on_off)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-31 18:55:57 +02:00
|
|
|
long SpuSetReverb(long on_off)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long SpuSetReverbVoice(long on_off, unsigned long voice_bit)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpuSetCommonAttr(SpuCommonAttr* attr)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
2020-04-08 20:07:11 +02:00
|
|
|
static long s_spuMallocVal = 0;
|
|
|
|
|
2020-03-31 18:55:57 +02:00
|
|
|
long SpuInitMalloc(long num, char* top)//(F)
|
|
|
|
{
|
2020-04-08 20:07:11 +02:00
|
|
|
s_spuMallocVal = 0;
|
|
|
|
|
2020-03-31 18:55:57 +02:00
|
|
|
if (num > 0)
|
|
|
|
{
|
|
|
|
//loc_214
|
|
|
|
((int*)top)[0] = 0x40001010;
|
|
|
|
_spu_memList = (uintptr_t)top;
|
|
|
|
_spu_AllocLastNum = 0;
|
|
|
|
_spu_AllocBlockNum = num;
|
|
|
|
((int*)top)[1] = (0x10000000 << _spu_mem_mode_plus) - 0x1010;
|
|
|
|
}
|
|
|
|
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
long SpuMalloc(long size)
|
|
|
|
{
|
2020-04-08 20:07:11 +02:00
|
|
|
int addr = s_spuMallocVal;
|
|
|
|
s_spuMallocVal += size;
|
|
|
|
|
|
|
|
return s_spuMallocVal; /*(long)(uintptr_t)malloc(size)*/;
|
2020-03-31 18:55:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
long SpuMallocWithStartAddr(unsigned long addr, long size)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpuFree(unsigned long addr)
|
|
|
|
{
|
|
|
|
/*free((void*)(uintptr_t)addr)*/;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpuSetCommonMasterVolume(short mvol_left, short mvol_right)// (F)
|
|
|
|
{
|
|
|
|
//MasterVolume.VolumeLeft.Raw = mvol_left;
|
|
|
|
//MasterVolume.VolumeRight.Raw = mvol_right;
|
|
|
|
}
|
|
|
|
|
|
|
|
long SpuSetReverbModeType(long mode)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpuSetReverbModeDepth(short depth_left, short depth_right)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
2020-04-04 15:42:29 +02:00
|
|
|
|
|
|
|
void SpuSetVoiceVolume(int vNum, short volL, short volR)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpuSetVoicePitch(int vNum, unsigned short pitch)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
2020-04-09 15:55:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void SpuSetVoiceAR(int vNum, unsigned short AR)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpuSetVoiceRR(int vNum, unsigned short RR)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|