REDRIVER2/src_rebuild/Game/C/xaplay.c
2022-01-21 21:01:06 +03:00

493 lines
8.1 KiB
C

#include "driver2.h"
#include "xaplay.h"
#include "camera.h"
#include "fmvplay.h"
#include "pause.h"
#include "platform.h"
#include "sound.h"
#include "pres.h"
#include "system.h"
#include "spool.h"
#ifndef PSX
#include <strings.h>
#include "../utils/riff.h"
#include "../utils/audio_source/snd_al_source.h"
#include "../utils/audio_source/snd_wav_cache.h"
#include "AL/al.h"
#ifndef __EMSCRIPTEN__
#include "AL/alext.h"
#endif // __EMSCRIPTEN__
const char* XANameFormat = "%sXA\\XABNK0%d.XA[%d].wav";
ALuint g_XASource = AL_NONE;
CSoundSource_WaveCache* g_wavData = NULL;
CSoundSource_OpenALCache* g_XAWave = NULL;
#else
#include <libsnd.h>
char* XANames[] = {
"%sXA\\XABNK01.XA;1",
"%sXA\\XABNK02.XA;1",
"%sXA\\XABNK03.XA;1",
"%sXA\\XABNK04.XA;1",
};
#endif
struct XA_TRACK
{
int start;
int end;
};
XA_TRACK XAMissionMessages[4];
static unsigned long finished_count = 0;
static int gPlaying = 0;
unsigned short gChannel = 0;
static int xa_prepared = 0;
static unsigned short CurrentChannel;
static unsigned short ID;
static int StartPos;
static CdlLOC pause_loc;
static u_int buffer[8];
#ifndef PSX
struct XA_SUBTITLE
{
char text[48];
int startframe;
int endframe;
};
void StoreXASubtitles()
{
int i, j;
char fileName[250];
for (i = 0; i < 4; i++)
{
for (j = 0; j < 8; j++)
{
sprintf(fileName, XANameFormat, gDataFolder, i+1, j);
FS_FixPathSlashes(fileName);
CSoundSource_WaveCache tmpWav;
if (tmpWav.Load(fileName))
{
// Save subtitles file
sprintf(fileName, "%sXA\\XABNK0%d.XA[%d].SBN", gDataFolder, i+1, j);
FS_FixPathSlashes(fileName);
FILE* fp = fopen(fileName, "wb");
if (fp)
{
int numSubtitles = tmpWav.m_numSubtitles;
XA_SUBTITLE subtitles[30];
// save subtitle count
fwrite(&numSubtitles, sizeof(int), 1, fp);
for (int i = 0; i < numSubtitles; i++)
{
CUESubtitle_t* sub = &tmpWav.m_subtitles[i];
strcpy(subtitles[i].text, sub->text);
subtitles[i].startframe = sub->sampleStart;
subtitles[i].endframe = sub->sampleStart + sub->sampleLength;
}
// write all subtitles
fwrite(subtitles, sizeof(XA_SUBTITLE), numSubtitles, fp);
fclose(fp);
}
}
}
}
}
XA_SUBTITLE gXASubtitles[30];
int gNumXASubtitles = 0;
int gXASubtitleTime = 0;
int gXASubtitlePauseTime = 0;
void PrintXASubtitles()
{
if (gSubtitles == 0 || pauseflag)
return;
if (gPlaying == 0 || g_wavData == NULL)
return;
int curTime = (VSync(-1) - gXASubtitleTime) * 17;
// find subtitles
for(int i = 0; i < gNumXASubtitles; i++)
{
XA_SUBTITLE* sub = &gXASubtitles[i];
int subStartFrame = sub->startframe;
int subEndFrame = sub->endframe;
if(curTime >= subStartFrame && curTime <= subEndFrame)
{
SetTextColour(120, 120, 120);
PrintStringCentred(sub->text, 200);
}
}
}
#endif
// [D] [T]
void GetMissionXAData(int number)
{
#ifdef PSX
CdlFILE fp;
char filename[64];
sprintf(filename, XANames[number], gDataFolder);
CdSearchFile(&fp, XANames[number]);
XAMissionMessages[number].start = CdPosToInt((CdlLOC *)&fp);
#endif
}
// [D] [T]
void GetXAData(int number)
{
int i;
if (number < 0)
{
i = 0;
do {
GetMissionXAData(i++);
} while (i < 4);
}
else
{
GetMissionXAData(number);
}
}
// [D] [T]
void SetXAVolume(int volume)
{
short vol;
vol = volume / 78 + 127;
if (vol == -1)
vol = 0;
#ifdef PSX
SsSetSerialVol(0, vol, vol);
#endif
}
CdlCB oldreadycallback;
void* olddatacallback;
void cbready(int intr, unsigned char *result);
// [D] [T]
void PrepareXA(void)
{
#ifdef PSX
u_char param[4];
finished_count = 0;
gPlaying = 0;
if (xa_prepared == 0)
{
if (spoolactive && chunk_complete)
spoolpos_reading--;
CdInit();
param[0] = 0xE8;
CdControlB(CdlSetmode, param, 0);
oldreadycallback = CdReadyCallback((CdlCB)cbready);
olddatacallback = CdDataCallback(0);
xa_prepared = 1;
AllocateReverb(3, 0x4000);
}
#else
finished_count = 0;
gPlaying = 0;
if (xa_prepared == 0)
{
alGenSources(1, &g_XASource);
alSourcei(g_XASource, AL_LOOPING, 0);
#ifndef __EMSCRIPTEN__
alSourcei(g_XASource, AL_SOURCE_RESAMPLER_SOFT, 2); // Use cubic resampler
#endif // __EMSCRIPTEN__
alSourcei(g_XASource, AL_SOURCE_RELATIVE, AL_TRUE);
if (g_XAWave)
{
delete g_XAWave;
g_XAWave = NULL;
}
xa_prepared = 1;
}
#endif
}
// [D] [T]
void PlayXA(int num, int index)
{
short vol;
#ifdef PSX
CdlFILTER filt;
CdlLOC loc;
u_char res[8];
if (xa_prepared && gPlaying != 1)
{
filt.chan = index;
StartPos = XAMissionMessages[num].start;
gChannel = index;
filt.file = 1;
vol = (10000 + gMasterVolume) / 79;
SsSetSerialVol(0, vol, vol);
CdControlB(CdlSetfilter, (u_char*)&filt, res);
CdIntToPos(StartPos, &loc);
CdControlB(CdlReadS, (u_char*)&loc, res);
AllocateReverb(3, 0x4000);
gPlaying = 1;
xa_prepared = 2;
}
#else
if (xa_prepared && gPlaying != 1)
{
char fileName[250];
sprintf(fileName, XANameFormat, gDataFolder, num+1, index);
FS_FixPathSlashes(fileName);
g_wavData = new CSoundSource_WaveCache();
if (g_wavData->Load(fileName))
{
// make OpenAL buffer
g_XAWave = new CSoundSource_OpenALCache(g_wavData);
alSourcei(g_XASource, AL_BUFFER, g_XAWave->m_alBuffer);
vol = (10000 + gMasterVolume) / 79;
alSourcef(g_XASource, AL_GAIN, float(vol) / 128.0f);
alSourcePlay(g_XASource);
}
// Load subtitles for XA
sprintf(fileName, "%sXA\\XABNK0%d.XA[%d].SBN", gDataFolder, num + 1, index);
FS_FixPathSlashes(fileName);
FILE* fp = fopen(fileName, "rb");
if (fp)
{
fread(&gNumXASubtitles, sizeof(int), 1, fp);
fread(gXASubtitles, sizeof(XA_SUBTITLE), gNumXASubtitles, fp);
fclose(fp);
}
gPlaying = 1;
xa_prepared = 2;
gXASubtitleTime = VSync(-1);
}
#endif
}
// [D] [T]
int XAPrepared(void)
{
#ifndef PSX
if (g_XASource == AL_NONE)
return xa_prepared;
ALint sourceState;
alGetSourcei(g_XASource, AL_SOURCE_STATE, &sourceState);
if (sourceState == AL_STOPPED)
UnprepareXA();
#endif
return xa_prepared;
}
// [D] [T]
void UnprepareXA(void)
{
#ifdef PSX
u_char param[4];
if (xa_prepared != 0)
{
CdReadyCallback(oldreadycallback);
CdDataCallback((void (*)())olddatacallback);
param[0] = 0x80;
CdControlB(CdlSetmode, param, 0);
gPlaying = 0;
xa_prepared = 0;
}
#else
if (xa_prepared)
{
alSourceStop(g_XASource);
alDeleteSources(1, &g_XASource);
if (g_XAWave)
{
delete g_wavData;
g_wavData = NULL;
delete g_XAWave;
g_XAWave = NULL;
}
gPlaying = 0;
xa_prepared = 0;
g_XASource = AL_NONE;
}
#endif
}
// [D] [T]
void StopXA(void)
{
if (gPlaying && xa_prepared)
{
#ifdef PSX
SsSetSerialVol(0, 0, 0);
CdControlF(CdlPause, 0);
#else
alSourcePause(g_XASource);
#endif
gPlaying = 0;
}
}
// [D]
void cbready(int intr, unsigned char *result)
{
UNIMPLEMENTED();
#if 0
if (intr == 1)
{
CdGetSector(buffer, 8);
ID = buffer[3];
CurrentChannel = ((u_int)buffer[3] & 0x7c00) >> 10; // there is buffer[3]+2 bytes
if (buffer[3] == 0x160)
{
finished_count = finished_count | 1 << (CurrentChannel + 1 & 0x1f);
if (CurrentChannel == gChannel || finished_count == 0xff)
{
SsSetSerialVol(0, 0, 0);
CdControlF(CdlPause, 0);
gPlaying = 0;
finished_count = 0;
}
}
}
#endif
}
// [D] [T]
void ResumeXA(void)
{
short vol;
#ifdef PSX
CdlFILTER filt;
u_char res[8];
if (xa_prepared && gPlaying != 1)
{
filt.file = 1;
filt.chan = gChannel;
vol = (10000 + gMasterVolume) / 79;
SsSetSerialVol(0, vol, vol);
CdControlB(CdlSetfilter, (u_char*)&filt, res);
CdControlB(CdlReadS, (u_char*)&pause_loc, res);
AllocateReverb(3, 0x4000);
gPlaying = 1;
}
#else
if (xa_prepared && gPlaying)
{
vol = (10000 + gMasterVolume) / 79;
alSourcef(g_XASource, AL_GAIN, float(vol) / 128.0f);
alSourcePlay(g_XASource);
gXASubtitleTime += VSync(-1) - gXASubtitlePauseTime;
}
#endif
}
// [D] [T]
void PauseXA(void)
{
#ifdef PSX
u_char res[8];
if (xa_prepared && gPlaying)
{
SsSetSerialVol(0, 0, 0);
CdControlB(CdlGetlocL, 0, res);
pause_loc.minute = res[0];
pause_loc.second = res[1];
pause_loc.sector = res[2];
CdControlB(CdlPause, 0, 0);
gPlaying = 0;
}
#else
if (xa_prepared && gPlaying)
{
alSourcePause(g_XASource);
gXASubtitlePauseTime = VSync(-1);
}
#endif
}