mirror of
https://github.com/open-goal/jak-project
synced 2026-08-07 02:06:59 -04:00
8a73c3e997
This implements the functionality for the `PLUGIN_MESSAGE` grain and the 989snd VAG plugin system, allowing sounds to queue up VAG streams. Closes #2582
1059 lines
28 KiB
C++
1059 lines
28 KiB
C++
#include "vag.h"
|
|
|
|
#include <cstring>
|
|
|
|
#include "common/log/log.h"
|
|
#include "common/util/Assert.h"
|
|
|
|
#include "game/overlord/jak3/basefile.h"
|
|
#include "game/overlord/jak3/iso.h"
|
|
#include "game/overlord/jak3/iso_queue.h"
|
|
#include "game/overlord/jak3/spustreams.h"
|
|
#include "game/overlord/jak3/srpc.h"
|
|
#include "game/overlord/jak3/ssound.h"
|
|
#include "game/overlord/jak3/streamlist.h"
|
|
#include "game/sce/iop.h"
|
|
#include "game/sound/sdshim.h"
|
|
#include "game/sound/sndshim.h"
|
|
|
|
#define VOICE_BIT(voice) (1 << ((voice) >> 1))
|
|
|
|
namespace jak3 {
|
|
using namespace iop;
|
|
|
|
bool g_bExtPause = false;
|
|
bool g_bExtResume = false;
|
|
ISO_VAGCommand g_aVagCmds[6];
|
|
int g_anMasterVolume[32];
|
|
bool voice_key_flags[0x30];
|
|
u32 voice_key_times[0x30];
|
|
u32 g_nTimeOfLastVoiceKey = 0;
|
|
bool g_bRecentlyKeyedVoice = false;
|
|
u32 g_nActiveVagStreams = 0;
|
|
u32 g_nPlaybackMode = 2;
|
|
|
|
struct VagCmdPriListEntry {
|
|
ISO_VAGCommand* cmds[6];
|
|
};
|
|
|
|
VagCmdPriListEntry g_aapVagCmdsPriList[11];
|
|
u32 g_anVagCmdPriCounter[11];
|
|
|
|
void jak3_overlord_init_globals_vag() {
|
|
g_bExtPause = false;
|
|
g_bExtResume = false;
|
|
for (auto& c : g_aVagCmds) {
|
|
c = {};
|
|
}
|
|
for (auto& x : g_anMasterVolume) {
|
|
x = 0x400;
|
|
}
|
|
g_nActiveVagStreams = 0;
|
|
g_nPlaybackMode = 2;
|
|
}
|
|
|
|
void ISO_VAGCommand::set_all_flags_zero() {
|
|
flags.bit0 = 0;
|
|
flags.saw_chunks1 = 0;
|
|
flags.paused = 0;
|
|
flags.bit3 = 0;
|
|
|
|
flags.running = 0;
|
|
flags.clocks_set = 0;
|
|
flags.file_disappeared = 0;
|
|
flags.scanned = 0;
|
|
|
|
flags.bit8 = 0;
|
|
flags.stop = 0;
|
|
flags.art = 0;
|
|
flags.stereo_secondary = 0;
|
|
flags.bit12 = 0;
|
|
flags.bit13 = 0;
|
|
flags.bit14 = 0;
|
|
flags.bit15 = 0;
|
|
flags.bit16 = 0;
|
|
flags.bit17 = 0;
|
|
flags.dma_complete_even_chunk_count = 0;
|
|
flags.dma_complete_odd_chunk_count = 0;
|
|
flags.bit20 = 0;
|
|
flags.bit21 = 0;
|
|
flags.bit22 = 0;
|
|
flags.nostart = 0;
|
|
flags.movie = 0;
|
|
flags.bit25 = 0;
|
|
}
|
|
|
|
u32 ISO_VAGCommand::pack_flags() {
|
|
u32 ret = 0;
|
|
u8* ptr = &flags.bit0;
|
|
u32 mask = 1;
|
|
for (; ptr <= &flags.bit25; ptr++) {
|
|
if (*ptr) {
|
|
ret |= mask;
|
|
}
|
|
mask <<= 1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void InitVAGCmd(ISO_VAGCommand* cmd, int paused) {
|
|
set_active_a(cmd, 0);
|
|
set_active_b(cmd, 0);
|
|
set_active_c(cmd, 0);
|
|
cmd->set_all_flags_zero();
|
|
cmd->unk_gvsp_state2 = 0;
|
|
cmd->lfo_callback = nullptr;
|
|
if (paused == 0) {
|
|
cmd->flags.paused = 0;
|
|
} else {
|
|
cmd->flags.paused = 1;
|
|
}
|
|
cmd->safe_to_modify_dma = 1;
|
|
cmd->unk_spu_mem_offset = 0x4000;
|
|
cmd->callback = NullCallback;
|
|
cmd->dma_chan = -1;
|
|
cmd->fo_min = 5;
|
|
cmd->fo_max = 0x1e;
|
|
cmd->unk_gvsp_len = 0;
|
|
cmd->position_for_ee = 0;
|
|
cmd->unk_gvsp_cntr = 0;
|
|
cmd->clocka = 0;
|
|
cmd->clockb = 0;
|
|
cmd->clockc = 0;
|
|
cmd->clockd = 0;
|
|
cmd->flags.clocks_set = 0;
|
|
cmd->flags.file_disappeared = 0;
|
|
cmd->num_isobuffered_chunks = 0;
|
|
cmd->xfer_size = 0;
|
|
cmd->vag_file_rate = 0;
|
|
cmd->error = 0;
|
|
cmd->unk_gvsp_flag = 0;
|
|
cmd->m_pBaseFile = nullptr;
|
|
cmd->stereo_sibling = nullptr;
|
|
cmd->dma_iop_mem_ptr = nullptr;
|
|
cmd->pitch_cmd = 0;
|
|
cmd->updated_trans = 0;
|
|
cmd->trans[0] = 0;
|
|
cmd->trans[1] = 0;
|
|
cmd->trans[2] = 0;
|
|
cmd->fo_curve = GetFalloffCurve(1);
|
|
cmd->play_group = 2;
|
|
set_active_a(cmd, 1);
|
|
set_active_b(cmd, 1);
|
|
}
|
|
|
|
void InitVagCmds() {
|
|
auto now = GetSystemTimeLow();
|
|
for (auto& x : voice_key_flags) {
|
|
x = false;
|
|
}
|
|
for (auto& x : voice_key_times) {
|
|
x = now;
|
|
}
|
|
g_nTimeOfLastVoiceKey = 0;
|
|
g_bRecentlyKeyedVoice = false;
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
auto* cmd = &g_aVagCmds[i];
|
|
InitVAGCmd(cmd, 1);
|
|
cmd->info_idx = i;
|
|
cmd->stream_sram = g_auStrmSRAM[i];
|
|
cmd->trap_sram = g_auTrapSRAM[i];
|
|
cmd->voice = g_anStreamVoice[i];
|
|
cmd->music_flag = i >= 4;
|
|
cmd->file_def = nullptr;
|
|
cmd->vag_file_def = nullptr;
|
|
cmd->vag_dir_entry = nullptr;
|
|
cmd->flags.saw_chunks1 = 0;
|
|
cmd->play_volume = 0;
|
|
cmd->pitch_cmd = 0;
|
|
cmd->id = 0;
|
|
cmd->plugin_id = 0;
|
|
cmd->maybe_sound_handler = 0;
|
|
cmd->oog = 0;
|
|
cmd->dolby_pan_angle = 0;
|
|
cmd->priority_pq = 0;
|
|
cmd->art_flag = 0;
|
|
cmd->movie_flag = 0;
|
|
}
|
|
|
|
for (auto& level : g_aapVagCmdsPriList) {
|
|
for (auto& cmd : level.cmds) {
|
|
cmd = nullptr;
|
|
}
|
|
}
|
|
for (auto& x : g_anVagCmdPriCounter) {
|
|
x = 0;
|
|
}
|
|
// oops - wrong value from jak 2 maybe?
|
|
g_anVagCmdPriCounter[0] = 4;
|
|
}
|
|
|
|
void RemoveVagCmd(ISO_VAGCommand* cmd) {
|
|
ASSERT(cmd);
|
|
ASSERT(!cmd->music_flag);
|
|
ASSERT(cmd->info_idx < 4);
|
|
ASSERT(cmd->priority_pq >= 0 && cmd->priority_pq <= 10);
|
|
|
|
g_aapVagCmdsPriList[cmd->priority_pq].cmds[cmd->info_idx] = nullptr;
|
|
if (g_anVagCmdPriCounter[cmd->priority_pq]) {
|
|
g_anVagCmdPriCounter[cmd->priority_pq]--;
|
|
} else {
|
|
ASSERT_NOT_REACHED();
|
|
}
|
|
g_anVagCmdPriCounter[0]++;
|
|
}
|
|
|
|
ISO_VAGCommand* FindFreeVagCmd() {
|
|
for (int i = 0; i < 4; i++) {
|
|
if (g_aVagCmds[i].id == 0) {
|
|
return &g_aVagCmds[i];
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void SetNewVagCmdPri(ISO_VAGCommand* cmd, int pri) {
|
|
ASSERT(cmd);
|
|
ASSERT(!cmd->music_flag);
|
|
ASSERT(cmd->info_idx < 4);
|
|
ASSERT(pri >= 0 && pri <= 10);
|
|
auto old_pri = cmd->priority_pq;
|
|
g_aapVagCmdsPriList[old_pri].cmds[cmd->info_idx] = nullptr;
|
|
if (0 < g_anVagCmdPriCounter[old_pri]) {
|
|
g_anVagCmdPriCounter[old_pri]--;
|
|
} else {
|
|
ASSERT_NOT_REACHED();
|
|
}
|
|
g_anVagCmdPriCounter[pri]++;
|
|
cmd->priority_pq = pri;
|
|
g_aapVagCmdsPriList[pri].cmds[cmd->info_idx] = cmd;
|
|
}
|
|
|
|
int HowManyBelowThisPriority(int max_pri) {
|
|
int count = 0;
|
|
for (int i = 0; i < max_pri; i++) {
|
|
count += g_anVagCmdPriCounter[i];
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/*!
|
|
* The "smart"ness of this function is less than advertised.
|
|
*/
|
|
ISO_VAGCommand* SmartAllocMusicVagCommand(const ISO_VAGCommand* user_command, int flag) {
|
|
ASSERT(user_command);
|
|
int idx = flag ? 5 : 4;
|
|
auto* cmd = &g_aVagCmds[idx];
|
|
if (cmd->id == 0) {
|
|
g_nActiveMusicStreams++;
|
|
}
|
|
return cmd;
|
|
}
|
|
|
|
ISO_VAGCommand* SmartAllocVagCmd(ISO_VAGCommand* user_cmd) {
|
|
ASSERT(user_cmd);
|
|
ISO_VAGCommand* cmd = FindFreeVagCmd();
|
|
if (!cmd && (cmd = FindNotQueuedVagCmd(), !cmd)) {
|
|
u32 pri = 0;
|
|
if ((user_cmd->priority_pq != 0) && (pri = 0, user_cmd->priority_pq != 0)) {
|
|
do {
|
|
u32 cmd_idx = 0;
|
|
do {
|
|
auto* pIVar1 = g_aapVagCmdsPriList[pri].cmds[cmd_idx];
|
|
if (pIVar1 && (cmd = pIVar1, pIVar1->flags.stereo_secondary == 0)) {
|
|
pri = user_cmd->priority_pq;
|
|
cmd_idx = 4;
|
|
cmd = pIVar1;
|
|
}
|
|
cmd_idx = cmd_idx + 1;
|
|
} while (cmd_idx < 4);
|
|
pri = pri + 1;
|
|
} while (pri < (u32)user_cmd->priority_pq);
|
|
}
|
|
if (!cmd) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
g_nActiveVagStreams = g_nActiveVagStreams + 1;
|
|
return cmd;
|
|
}
|
|
|
|
void FreeVagCmd(ISO_VAGCommand* cmd) {
|
|
set_active_a(cmd, 0);
|
|
set_active_b(cmd, 0);
|
|
set_active_c(cmd, 0);
|
|
cmd->set_all_flags_zero();
|
|
|
|
cmd->flags.paused = 1;
|
|
cmd->flags.saw_chunks1 = 0;
|
|
cmd->flags.scanned = 0;
|
|
cmd->clocka = 0;
|
|
cmd->clockb = 0;
|
|
cmd->clockc = 0;
|
|
cmd->clockd = 0;
|
|
SetVagStreamName(cmd, 0);
|
|
cmd->safe_to_modify_dma = 1;
|
|
cmd->unk_spu_mem_offset = 0x4000;
|
|
cmd->callback = NullCallback;
|
|
cmd->dma_chan = -1;
|
|
cmd->lfo_callback = 0;
|
|
cmd->pitch1 = 0;
|
|
cmd->pitch1_file = 0;
|
|
cmd->file_def = nullptr;
|
|
cmd->vag_file_def = nullptr;
|
|
cmd->vag_dir_entry = nullptr;
|
|
cmd->unk_gvsp_len = 0;
|
|
cmd->position_for_ee = 0;
|
|
cmd->unk_gvsp_cntr = 0;
|
|
cmd->name[0] = 0;
|
|
cmd->num_isobuffered_chunks = 0;
|
|
cmd->xfer_size = 0;
|
|
cmd->vag_file_rate = 0;
|
|
cmd->error = 0;
|
|
cmd->unk_gvsp_flag = 0;
|
|
cmd->play_volume = 0;
|
|
cmd->pitch_cmd = 0;
|
|
cmd->id = 0;
|
|
cmd->plugin_id = 0;
|
|
cmd->maybe_sound_handler = 0;
|
|
cmd->priority_pq = 0;
|
|
cmd->art_flag = 0;
|
|
cmd->movie_flag = 0;
|
|
cmd->updated_trans = 0;
|
|
cmd->m_pBaseFile = nullptr;
|
|
cmd->dma_iop_mem_ptr = nullptr;
|
|
cmd->unk_gvsp_state2 = 0;
|
|
if (!cmd->music_flag) {
|
|
if (0 < g_nActiveVagStreams) {
|
|
g_nActiveVagStreams = g_nActiveVagStreams + -1;
|
|
} else {
|
|
ASSERT_NOT_REACHED();
|
|
}
|
|
} else {
|
|
if (0 < g_nActiveMusicStreams) {
|
|
g_nActiveMusicStreams = g_nActiveMusicStreams + -1;
|
|
} else {
|
|
ASSERT_NOT_REACHED();
|
|
}
|
|
}
|
|
// CpuResumeIntr(local_10[0]);
|
|
}
|
|
|
|
void SetVagStreamsNotScanned() {
|
|
for (int i = 0; i < 4; i++) {
|
|
g_aVagCmds[i].flags.scanned = false;
|
|
}
|
|
}
|
|
|
|
void SetVagStreamsNoStart(int value) {
|
|
for (int i = 0; i < 4; i++) {
|
|
g_aVagCmds[i].flags.nostart = value;
|
|
}
|
|
}
|
|
|
|
ISO_VAGCommand* FindNotQueuedVagCmd() {
|
|
for (int i = 0; i < 4; i++) {
|
|
auto* cmd = &g_aVagCmds[i];
|
|
if (!cmd->flags.scanned && !cmd->flags.stereo_secondary && !cmd->flags.running) {
|
|
return cmd;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
int AnyVagRunning() {
|
|
int count = 0;
|
|
for (int i = 0; i < 4; i++) {
|
|
if (g_aVagCmds[i].flags.running) {
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
ISO_VAGCommand* FindVagStreamPluginId(int id) {
|
|
if (id == 0) {
|
|
return nullptr;
|
|
}
|
|
for (int i = 0; i < 4; i++) {
|
|
auto* cmd = &g_aVagCmds[i];
|
|
if (cmd->plugin_id == id) {
|
|
return cmd;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
ISO_VAGCommand* FindVagStreamId(int id) {
|
|
if (id == 0) {
|
|
return nullptr;
|
|
}
|
|
for (int i = 0; i < 4; i++) {
|
|
auto* cmd = &g_aVagCmds[i];
|
|
if (cmd->id == id) {
|
|
return cmd;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
ISO_VAGCommand* FindVagStreamName(const char* name) {
|
|
for (int i = 0; i < 4; i++) {
|
|
auto* cmd = &g_aVagCmds[i];
|
|
if (strcmp(cmd->name, name) == 0) {
|
|
return cmd;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
ISO_VAGCommand* FindThisVagStream(const char* name, int id) {
|
|
for (int i = 0; i < 4; i++) {
|
|
auto* cmd = &g_aVagCmds[i];
|
|
if (strcmp(cmd->name, name) == 0 && cmd->id == id) {
|
|
return cmd;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
ISO_VAGCommand* FindMusicStreamName(const char* name) {
|
|
for (int i = 4; i < 6; i++) {
|
|
auto* cmd = &g_aVagCmds[i];
|
|
if (strcmp(cmd->name, name) == 0) {
|
|
return cmd;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
ISO_VAGCommand* FindThisMusicStream(const char* name, int id) {
|
|
for (int i = 4; i < 6; i++) {
|
|
auto* cmd = &g_aVagCmds[i];
|
|
if (strcmp(cmd->name, name) == 0 && cmd->id == id) {
|
|
return cmd;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/*!
|
|
* Immediately stop the audio playback of a command, without the ability to resume.
|
|
* This will key off voices.
|
|
*/
|
|
void StopVAG(ISO_VAGCommand* cmd) {
|
|
// mark buffer inactive, so we don't stream more data
|
|
set_active_a(cmd, 0);
|
|
set_active_b(cmd, 0);
|
|
|
|
// safely pause playback
|
|
PauseVAG(cmd);
|
|
|
|
// deal with SPU voices:
|
|
if (cmd->flags.clocks_set) {
|
|
// do individual voice blocks
|
|
u32 voice_mask = VOICE_BIT(cmd->voice);
|
|
BlockUntilVoiceSafe(cmd->voice, 0x900);
|
|
auto* sibling = cmd->stereo_sibling;
|
|
if (sibling) {
|
|
voice_mask |= VOICE_BIT(sibling->voice);
|
|
BlockUntilVoiceSafe(sibling->voice, 0x900);
|
|
}
|
|
BlockUntilAllVoicesSafe();
|
|
|
|
sceSdSetSwitch((cmd->voice & 1) | SD_S_KOFF, voice_mask);
|
|
|
|
auto now = GetSystemTimeLow();
|
|
MarkVoiceKeyedOnOff(cmd->voice, now);
|
|
if (sibling) {
|
|
MarkVoiceKeyedOnOff(sibling->voice, now);
|
|
}
|
|
}
|
|
|
|
// clear out command
|
|
cmd->set_all_flags_zero();
|
|
cmd->callback = NullCallback;
|
|
cmd->clockd = 0;
|
|
cmd->play_volume = 0;
|
|
cmd->pitch_cmd = 0;
|
|
cmd->id = 0;
|
|
cmd->plugin_id = 0;
|
|
cmd->maybe_sound_handler = 0;
|
|
cmd->lfo_callback = 0;
|
|
cmd->pitch1 = 0;
|
|
cmd->pitch1_file = 0;
|
|
cmd->clocka = 0;
|
|
cmd->clockb = 0;
|
|
cmd->clockc = 0;
|
|
}
|
|
|
|
/*!
|
|
* Stop a VAG, also remove it from lists of active commands.
|
|
*/
|
|
void TerminateVAG(ISO_VAGCommand* in_cmd) {
|
|
// ISO_VAGCommand *sibling;
|
|
// VagStreamData vsd;
|
|
// undefined auStack64 [36];
|
|
// int local_1c;
|
|
// int local_18;
|
|
// bool not_music;
|
|
ASSERT(in_cmd);
|
|
bool not_music = !in_cmd->music_flag;
|
|
VagStreamData vsd;
|
|
strncpy(vsd.name, in_cmd->name, 0x30);
|
|
vsd.id = in_cmd->id;
|
|
StopVAG(in_cmd);
|
|
ReleaseMessage(in_cmd);
|
|
if (not_music) {
|
|
RemoveVagCmd(in_cmd);
|
|
}
|
|
FreeVagCmd(in_cmd);
|
|
auto* sibling = in_cmd->stereo_sibling;
|
|
if (sibling) {
|
|
sibling->flags.scanned = 0;
|
|
if (not_music) {
|
|
RemoveVagCmd(sibling);
|
|
}
|
|
FreeVagCmd(sibling);
|
|
}
|
|
if (not_music) {
|
|
if (in_cmd->maybe_sound_handler != 0) {
|
|
RemoveVagStreamFromList(&vsd, &g_PluginStreamsList);
|
|
// TODO LFO support
|
|
// RemoveLfoStreamFromList(auStack64, &g_LfoStreamsList);
|
|
}
|
|
RemoveVagStreamFromList(&vsd, &g_EEPlayList);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Pause a vag stream by setting the volume to 0, the pitch to 0, then keying off the voice.
|
|
*/
|
|
void PauseVAG(ISO_VAGCommand* cmd) {
|
|
if (cmd->flags.paused == 0) {
|
|
// CpuSuspendIntr(local_18);
|
|
if (cmd->flags.stereo_secondary == 0) {
|
|
auto* sibling = cmd->stereo_sibling;
|
|
if (!sibling) {
|
|
if (cmd->flags.saw_chunks1) {
|
|
// this means we enabled volume before, so disable it.
|
|
static_assert(SD_VP_VOLL == 0);
|
|
static_assert(SD_VP_VOLR == 0x100);
|
|
static_assert(SD_VP_PITCH == 0x200);
|
|
sceSdSetParam(cmd->voice | SD_VP_VOLL, 0);
|
|
sceSdSetParam(cmd->voice | SD_VP_VOLR, 0);
|
|
}
|
|
|
|
// in either case, set pitch to 0 to stop playback.
|
|
sceSdSetParam(cmd->voice | SD_VP_PITCH, 0);
|
|
|
|
auto voice = cmd->voice;
|
|
BlockUntilVoiceSafe(voice, 0x900);
|
|
BlockUntilAllVoicesSafe();
|
|
// key off
|
|
sceSdSetSwitch((cmd->voice & 1) | SD_S_KOFF, VOICE_BIT(voice));
|
|
MarkVoiceKeyedOnOff(cmd->voice, GetSystemTimeLow());
|
|
|
|
// remember where to resume from
|
|
if (cmd->flags.clocks_set == 0) {
|
|
cmd->current_spu_address = 0;
|
|
} else {
|
|
cmd->current_spu_address = GetSpuRamAddress(cmd);
|
|
}
|
|
cmd->flags.paused = 1;
|
|
} else {
|
|
if (cmd->flags.saw_chunks1 != 0) {
|
|
sceSdSetParam(cmd->voice | SD_VP_VOLL, 0);
|
|
sceSdSetParam(cmd->voice | SD_VP_VOLR, 0);
|
|
sceSdSetParam(sibling->voice | SD_VP_VOLL, 0);
|
|
sceSdSetParam(sibling->voice | SD_VP_VOLR, 0);
|
|
}
|
|
sceSdSetParam(sibling->voice | SD_VP_PITCH, 0);
|
|
sceSdSetParam(cmd->voice | SD_VP_PITCH, 0);
|
|
auto sibling_voice = sibling->voice;
|
|
auto voice = cmd->voice;
|
|
BlockUntilVoiceSafe(voice, 0x900);
|
|
BlockUntilVoiceSafe(sibling->voice, 0x900);
|
|
BlockUntilAllVoicesSafe();
|
|
sceSdSetSwitch((cmd->voice & 1) | SD_S_KOFF,
|
|
(VOICE_BIT(voice)) | (VOICE_BIT(sibling_voice)));
|
|
auto now = GetSystemTimeLow();
|
|
MarkVoiceKeyedOnOff(cmd->voice, now);
|
|
MarkVoiceKeyedOnOff(sibling->voice, now);
|
|
if (cmd->flags.clocks_set == 0) {
|
|
cmd->current_spu_address = 0;
|
|
sibling->current_spu_address = 0;
|
|
} else {
|
|
u32 spu_ram_addr = GetSpuRamAddress(cmd);
|
|
cmd->current_spu_address = spu_ram_addr & 0xfffffff8;
|
|
sibling->current_spu_address =
|
|
((spu_ram_addr & 0xfffffff8) - cmd->stream_sram) + sibling->stream_sram;
|
|
}
|
|
cmd->flags.paused = 1;
|
|
sibling->flags.paused = 1;
|
|
}
|
|
}
|
|
// CpuResumeIntr(local_18[0]);
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
u32 read_rate_calc(u32 pitch) {
|
|
u64 pitch1 = (pitch >> 3);
|
|
u64 mult_result = pitch1 * 0x2492'4925ull;
|
|
return mult_result >> 32;
|
|
}
|
|
} // namespace
|
|
/*!
|
|
* Start up a VAG stream after it was paused. Also, used to start a vag stream for the first time.
|
|
*/
|
|
void UnPauseVAG(ISO_VAGCommand* cmd) {
|
|
if (cmd->flags.paused) {
|
|
// CpuSuspendIntr(&local_28);
|
|
if (cmd->flags.stereo_secondary == 0) {
|
|
auto* sibling = cmd->stereo_sibling;
|
|
auto pitch = CalculateVAGPitch(cmd->pitch1, cmd->pitch_cmd);
|
|
|
|
// calculate read rate
|
|
if (cmd->m_pBaseFile) {
|
|
auto p2 = CalculateVAGPitch(cmd->pitch1_file, cmd->pitch_cmd);
|
|
u32 rate;
|
|
if (sibling == (ISO_VAGCommand*)0x0) {
|
|
rate = p2 * 0x177;
|
|
} else {
|
|
rate = p2 * 0x2ee;
|
|
}
|
|
cmd->m_pBaseFile->m_ReadRate = read_rate_calc(rate);
|
|
}
|
|
|
|
int lvol, rvol;
|
|
CalculateVAGVolumes(cmd, &lvol, &rvol);
|
|
if (!sibling) {
|
|
// only update volume here if we've actually started the stream.
|
|
// otherwise, the stream is still getting set up, and the unpause will occur in
|
|
// the SPU interrupt handler.
|
|
if (cmd->flags.saw_chunks1) {
|
|
BlockUntilVoiceSafe(cmd->voice, 0x900);
|
|
if (cmd->current_spu_address != 0) {
|
|
sceSdSetAddr(cmd->voice | SD_VA_SSA, cmd->current_spu_address);
|
|
}
|
|
sceSdSetParam(cmd->voice | SD_VP_PITCH, pitch & 0xffff);
|
|
BlockUntilAllVoicesSafe();
|
|
// lg::error("keying on 1!");
|
|
sceSdSetSwitch((cmd->voice & 1) | SD_S_KON, VOICE_BIT(cmd->voice));
|
|
MarkVoiceKeyedOnOff(cmd->voice, GetSystemTimeLow());
|
|
sceSdSetParam(cmd->voice | SD_VP_VOLL, lvol);
|
|
sceSdSetParam(cmd->voice | SD_VP_VOLR, rvol);
|
|
}
|
|
cmd->flags.paused = 0;
|
|
} else {
|
|
if (cmd->flags.saw_chunks1) {
|
|
BlockUntilVoiceSafe(cmd->voice, 0x900);
|
|
BlockUntilVoiceSafe(sibling->voice, 0x900);
|
|
sceSdSetParam(cmd->voice | SD_VP_PITCH, pitch & 0xffff);
|
|
sceSdSetParam(sibling->voice | SD_VP_PITCH, pitch & 0xffff);
|
|
if (cmd->current_spu_address != 0) {
|
|
sceSdSetAddr(cmd->voice | SD_VA_SSA, cmd->current_spu_address);
|
|
sceSdSetAddr(sibling->voice | SD_VA_SSA, sibling->current_spu_address);
|
|
}
|
|
BlockUntilAllVoicesSafe();
|
|
sceSdSetSwitch((cmd->voice & 1) | SD_S_KON,
|
|
(VOICE_BIT(cmd->voice)) | (VOICE_BIT(sibling->voice)));
|
|
auto now = GetSystemTimeLow();
|
|
MarkVoiceKeyedOnOff(cmd->voice, now);
|
|
MarkVoiceKeyedOnOff(sibling->voice, now);
|
|
sceSdSetParam(cmd->voice | SD_VP_VOLL, lvol);
|
|
sceSdSetParam(sibling->voice | SD_VP_VOLL, 0);
|
|
sceSdSetParam(cmd->voice | SD_VP_VOLR, 0);
|
|
sceSdSetParam(sibling->voice | SD_VP_VOLR, rvol);
|
|
}
|
|
cmd->flags.paused = 0;
|
|
sibling->flags.paused = 0;
|
|
}
|
|
}
|
|
// CpuResumeIntr(local_28);
|
|
}
|
|
}
|
|
|
|
// TODO: needs some cleanup
|
|
void RestartVag(ISO_VAGCommand* cmd, int p) {
|
|
(void)p;
|
|
// CpuSuspendIntr(&local_28);
|
|
int lvol, rvol;
|
|
CalculateVAGVolumes(cmd, &lvol, &rvol);
|
|
if (cmd->flags.stereo_secondary == 0) {
|
|
auto* sibling = cmd->stereo_sibling;
|
|
u32 voice_mask = VOICE_BIT(cmd->voice);
|
|
BlockUntilVoiceSafe(cmd->voice, 0x900);
|
|
if (sibling) {
|
|
voice_mask |= VOICE_BIT(sibling->voice);
|
|
BlockUntilVoiceSafe(sibling->voice, 0x900);
|
|
}
|
|
BlockUntilAllVoicesSafe();
|
|
sceSdSetSwitch((cmd->voice & 1) | SD_S_KOFF, voice_mask);
|
|
sceSdSetParam(cmd->voice | SD_VP_VOLL, 0);
|
|
sceSdSetParam(cmd->voice | SD_VP_VOLR, 0);
|
|
// wtf is this crap
|
|
// CpuResumeIntr(local_28);
|
|
DelayThread(100);
|
|
// CpuSuspendIntr(&local_28);
|
|
u32 bVar1;
|
|
u32 uVar4;
|
|
if (sibling == (ISO_VAGCommand*)0x0) {
|
|
bVar1 = cmd->voice;
|
|
uVar4 = cmd->stream_sram;
|
|
} else {
|
|
sceSdSetParam(sibling->voice, 0);
|
|
sceSdSetParam(sibling->voice | 0x100, 0);
|
|
sceSdSetAddr(cmd->voice | 0x2040, cmd->stream_sram);
|
|
bVar1 = sibling->voice;
|
|
uVar4 = sibling->stream_sram;
|
|
}
|
|
sceSdSetAddr(bVar1 | 0x2040, uVar4);
|
|
BlockUntilAllVoicesSafe();
|
|
sceSdSetSwitch((cmd->voice & 1) | 0x1500, voice_mask);
|
|
auto uVar3 = GetSystemTimeLow();
|
|
MarkVoiceKeyedOnOff(cmd->voice, uVar3);
|
|
u32 uVar2;
|
|
if (!sibling) {
|
|
sceSdSetParam(cmd->voice, lvol);
|
|
uVar2 = cmd->voice;
|
|
} else {
|
|
MarkVoiceKeyedOnOff(sibling->voice, uVar3);
|
|
sceSdSetParam(cmd->voice, lvol);
|
|
sceSdSetParam(sibling->voice, 0);
|
|
sceSdSetParam(cmd->voice | 0x100, 0);
|
|
uVar2 = sibling->voice;
|
|
}
|
|
sceSdSetParam(uVar2 | 0x100, rvol);
|
|
}
|
|
// CpuResumeIntr(local_28);
|
|
}
|
|
|
|
void PauseVagStreams(bool music) {
|
|
if (music != 0) {
|
|
WaitSema(g_nMusicSemaphore);
|
|
g_bAnotherMusicPauseFlag = true;
|
|
g_bMusicIsPaused = true;
|
|
}
|
|
|
|
for (int i = 0; i < (music ? 6 : 4); i++) {
|
|
auto* cmd = &g_aVagCmds[i];
|
|
if (cmd->flags.running && !cmd->flags.paused) {
|
|
PauseVAG(cmd);
|
|
}
|
|
}
|
|
|
|
if (music != 0) {
|
|
SignalSema(g_nMusicSemaphore);
|
|
}
|
|
}
|
|
|
|
void UnPauseVagStreams(bool music) {
|
|
int iVar1;
|
|
ISO_VAGCommand* cmd;
|
|
|
|
if (music != 0) {
|
|
WaitSema(g_nMusicSemaphore);
|
|
}
|
|
cmd = g_aVagCmds;
|
|
iVar1 = 4;
|
|
if ((music != 0) && (iVar1 = 6, g_bMusicPause != 0)) {
|
|
iVar1 = 4;
|
|
}
|
|
while (iVar1 != 0) {
|
|
iVar1 = iVar1 + -1;
|
|
if ((cmd->flags.running != 0) && (cmd->flags.paused != 0)) {
|
|
UnPauseVAG(cmd);
|
|
}
|
|
cmd = cmd + 1;
|
|
}
|
|
if (music != 0) {
|
|
g_bAnotherMusicPauseFlag = false;
|
|
if (g_bMusicPause == 0) {
|
|
g_bMusicIsPaused = false;
|
|
}
|
|
SignalSema(g_nMusicSemaphore);
|
|
}
|
|
}
|
|
|
|
int CalculateDolbyPanAngle(ISO_VAGCommand* cmd, u32 angle) {
|
|
int iVar1;
|
|
int iVar2;
|
|
|
|
iVar1 = 0;
|
|
if (cmd != (ISO_VAGCommand*)0x0) {
|
|
if (0x167 < angle) {
|
|
// TODO: sus 64-bit multiply
|
|
angle = angle + (u32)((u64)(angle >> 3) * 0x16c16c17 >> 0x22) * -0x168;
|
|
}
|
|
iVar1 = cmd->dolby_pan_angle;
|
|
iVar2 = iVar1;
|
|
if (0x167 < iVar1) {
|
|
iVar2 = iVar1 + -0x168;
|
|
}
|
|
iVar2 = angle - iVar2;
|
|
if (iVar2 < -0xb4) {
|
|
iVar2 = iVar2 + 0x168;
|
|
} else {
|
|
if (0xb4 < iVar2) {
|
|
iVar2 = iVar2 + -0x168;
|
|
}
|
|
}
|
|
iVar1 = iVar1 + iVar2;
|
|
if (iVar1 < 0) {
|
|
iVar1 = iVar1 + 0x2d0;
|
|
}
|
|
if (0x2cf < iVar1) {
|
|
iVar1 = iVar1 + -0x2d0;
|
|
}
|
|
cmd->dolby_pan_angle = iVar1;
|
|
}
|
|
return iVar1;
|
|
}
|
|
|
|
void CalculateVAGVolumes(ISO_VAGCommand* cmd, int* lvol, int* rvol) {
|
|
u32 angle;
|
|
int iVar3;
|
|
int iVar4;
|
|
int iVar5;
|
|
u32 uVar7;
|
|
u32 uVar8;
|
|
int iVar9;
|
|
|
|
ASSERT(cmd && lvol && rvol);
|
|
|
|
iVar9 = g_nPlaybackMode;
|
|
iVar3 = 0x3fff;
|
|
iVar4 = 0x3fff;
|
|
uVar8 = 0;
|
|
if (cmd->music_flag == 0) {
|
|
iVar5 = cmd->maybe_sound_handler;
|
|
if (iVar5 == 0) {
|
|
if (cmd->updated_trans == 0) {
|
|
uVar7 = (u32)(cmd->play_volume * g_anMasterVolume[cmd->play_group]) >> 6;
|
|
goto LAB_0000bb58;
|
|
}
|
|
uVar7 = CalculateFalloffVolume(cmd->trans,
|
|
(cmd->play_volume * g_anMasterVolume[cmd->play_group]) >> 10,
|
|
cmd->fo_curve, cmd->fo_min, cmd->fo_max, 0, 0);
|
|
iVar3 = CalculateAngle(cmd->trans, cmd->fo_curve, 0);
|
|
angle = iVar3 + 0x5aU + (u32)((u64)((iVar3 + 0x5aU) >> 3) * 0x16c16c17 >> 0x22) * -0x168;
|
|
if (0x400 < uVar7) {
|
|
uVar7 = 0x400;
|
|
}
|
|
uVar7 = uVar7 << 4 | uVar7 >> 6;
|
|
} else {
|
|
s32 group = snd_GetSoundGroup(cmd->id) & 0x1f;
|
|
u32 vol = 0x3fff * (u32)((cmd->play_volume * g_anMasterVolume[group]) >> 10);
|
|
s32 pan_angle = (cmd->dolby_pan_angle + 90) % 360;
|
|
if (pan_angle < 0) {
|
|
pan_angle += 360;
|
|
}
|
|
s32 l = (g_aPanTable[pan_angle].left * (s32)(vol >> 10)) >> 10;
|
|
s32 r = (g_aPanTable[pan_angle].right * (s32)(vol >> 10)) >> 10;
|
|
if (l >= 0x4000) {
|
|
l = 0x3fff;
|
|
}
|
|
if (r >= 0x4000) {
|
|
r = 0x3fff;
|
|
}
|
|
*lvol = l;
|
|
*rvol = r;
|
|
return;
|
|
}
|
|
|
|
if (iVar9 == 1) {
|
|
iVar3 = 0x2d41;
|
|
iVar4 = 0x2d41;
|
|
} else {
|
|
if (iVar9 < 2) {
|
|
iVar3 = 0x2d41;
|
|
if (iVar9 == 0) {
|
|
// ASSERT_NOT_REACHED(); // dolby crap
|
|
// TODO:
|
|
iVar4 = 0x2d41;
|
|
// uVar8 = CalculateDolbyPanAngle(cmd, angle);
|
|
// iVar9 = (uint)((u64)(uVar8 >> 1) * 0xb60b60b7 >> 0x25) * 4;
|
|
// if (0x167 < uVar8) {
|
|
// uVar8 = uVar8 - 0x168;
|
|
// }
|
|
// if (uVar8 < 0xb4) {
|
|
// psVar6 = (short*)(g_aPanTable + uVar8 * 4);
|
|
// sVar1 = psVar6[1];
|
|
// sVar2 = *psVar6;
|
|
// } else {
|
|
// iVar3 = g_aPanTable + uVar8 * 4;
|
|
// sVar1 = *(short*)(iVar3 + -0x2d0);
|
|
// sVar2 = *(short*)(iVar3 + -0x2ce);
|
|
// }
|
|
// iVar4 = (int)sVar1;
|
|
// iVar3 = (int)sVar2;
|
|
// if ((int)((uint) * (ushort*)(iVar9 + 0x15800) << 0x10) < 0) {
|
|
// iVar3 = -iVar3;
|
|
// }
|
|
// if (*(short*)(iVar9 + 0x15802) < 0) {
|
|
// iVar4 = -iVar4;
|
|
// }
|
|
// uVar8 = 0xffffc001;
|
|
} else {
|
|
iVar4 = 0x2d41;
|
|
}
|
|
} else {
|
|
iVar3 = 0x2d41;
|
|
if (iVar9 == 2) {
|
|
cmd->dolby_pan_angle = angle;
|
|
if (angle < 0xb4) {
|
|
auto pte = g_aPanTable[angle];
|
|
// psVar6 = (short*)(g_aPanTable + angle * 4);
|
|
iVar4 = pte.right;
|
|
iVar3 = pte.left;
|
|
} else {
|
|
// iVar3 = g_aPanTable + angle * 4;
|
|
u32 angle2 = (angle - 180);
|
|
ASSERT(angle2 < 360);
|
|
auto pte = g_aPanTable[angle2];
|
|
iVar4 = pte.left;
|
|
iVar3 = pte.right;
|
|
}
|
|
} else {
|
|
iVar4 = 0x2d41;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
uVar7 = ((u32)(g_nMusicFade * g_anMasterVolume[1]) >> 0xc) * g_nMusicTweak >> 7;
|
|
}
|
|
|
|
LAB_0000bb58:
|
|
iVar9 = iVar4;
|
|
if (g_CameraInvert != 0) {
|
|
iVar9 = iVar3;
|
|
iVar3 = iVar4;
|
|
}
|
|
iVar3 = iVar3 * uVar7;
|
|
iVar9 = iVar9 * uVar7;
|
|
if (iVar3 < 0) {
|
|
iVar3 = iVar3 + 0x3fff;
|
|
}
|
|
uVar7 = iVar3 >> 0xe;
|
|
if (iVar9 < 0) {
|
|
iVar9 = iVar9 + 0x3fff;
|
|
}
|
|
angle = iVar9 >> 0xe;
|
|
if (0x3fff < (int)uVar7) {
|
|
uVar7 = 0x3fff;
|
|
}
|
|
if ((int)uVar7 < (int)uVar8) {
|
|
uVar7 = uVar8;
|
|
}
|
|
*lvol = uVar7 & 0x7fff;
|
|
if (0x3fff < (int)angle) {
|
|
angle = 0x3fff;
|
|
}
|
|
if ((int)angle < (int)uVar8) {
|
|
angle = uVar8;
|
|
}
|
|
*rvol = angle & 0x7fff;
|
|
}
|
|
|
|
s32 CalculateVAGPitch(int param_1, int param_2) {
|
|
if (param_2) {
|
|
if (param_2 <= 0) {
|
|
return 0x5f4 * param_1 / (0x5f4 - param_2);
|
|
} else {
|
|
return param_1 * (param_2 + 0x5f4) / 0x5f4;
|
|
}
|
|
}
|
|
|
|
return param_1;
|
|
// if (b != 0) {
|
|
// if (0 < b) {
|
|
// return (a * (b + 0x5f4)) / 0x5f4;
|
|
// }
|
|
// a = (a * 0x5f4) / (0x5f4U - b);
|
|
// }
|
|
// return a;
|
|
}
|
|
|
|
void SetVAGVol(ISO_VAGCommand* cmd) {
|
|
if (cmd && cmd->flags.running && !cmd->flags.paused && !cmd->flags.stereo_secondary) {
|
|
auto* sibling = cmd->stereo_sibling;
|
|
int lvol, rvol;
|
|
CalculateVAGVolumes(cmd, &lvol, &rvol);
|
|
auto* file = cmd->m_pBaseFile;
|
|
if (file) {
|
|
u32 rate = CalculateVAGPitch(cmd->pitch1_file, cmd->pitch_cmd);
|
|
if (!sibling) {
|
|
rate = rate * 0x177;
|
|
} else {
|
|
rate = rate * 0x2ee;
|
|
}
|
|
file->m_ReadRate = read_rate_calc(rate);
|
|
}
|
|
|
|
// like jak2, rewritten to not use sceSdProcBatch
|
|
if (!sibling) {
|
|
sceSdSetParam(SD_VP_VOLL | cmd->voice, lvol);
|
|
sceSdSetParam(SD_VP_VOLR | cmd->voice, rvol);
|
|
sceSdSetParam(SD_VP_PITCH | cmd->voice, CalculateVAGPitch(cmd->pitch1, cmd->pitch_cmd));
|
|
} else {
|
|
// left channel, left vol
|
|
if (g_CameraInvert) {
|
|
sceSdSetParam(SD_VP_VOLL | cmd->voice, 0);
|
|
} else {
|
|
sceSdSetParam(SD_VP_VOLL | cmd->voice, lvol);
|
|
}
|
|
|
|
// right channel, left vol
|
|
if (g_CameraInvert) {
|
|
sceSdSetParam(SD_VP_VOLL | sibling->voice, rvol);
|
|
} else {
|
|
sceSdSetParam(SD_VP_VOLL | sibling->voice, 0);
|
|
}
|
|
|
|
if (g_CameraInvert) {
|
|
sceSdSetParam(SD_VP_VOLR | cmd->voice, lvol);
|
|
} else {
|
|
sceSdSetParam(SD_VP_VOLR | cmd->voice, 0);
|
|
}
|
|
|
|
if (g_CameraInvert) {
|
|
sceSdSetParam(SD_VP_VOLR | sibling->voice, 0);
|
|
} else {
|
|
sceSdSetParam(SD_VP_VOLR | sibling->voice, rvol);
|
|
}
|
|
|
|
sceSdSetParam(SD_VP_PITCH | cmd->voice, CalculateVAGPitch(cmd->pitch1, cmd->pitch_cmd));
|
|
}
|
|
// CpuSuspendIntr(local_20);
|
|
// sceSdProcBatch(batch, 0, count);
|
|
// CpuResumeIntr(local_20[0]);
|
|
}
|
|
}
|
|
|
|
void SetAllVagsVol(int x) {
|
|
if (x < 0) {
|
|
for (int i = 0; i < 4; i++) {
|
|
SetVAGVol(&g_aVagCmds[i]);
|
|
}
|
|
} else {
|
|
for (int i = 0; i < 4; i++) {
|
|
if (g_aVagCmds[i].maybe_sound_handler && (snd_GetSoundGroup(g_aVagCmds[i].id) & 0x1f) == x) {
|
|
SetVAGVol(&g_aVagCmds[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void VAG_MarkLoopStart(uint8_t* data) {
|
|
data[0x11] = 2;
|
|
data[1] = 6;
|
|
}
|
|
|
|
void VAG_MarkLoopEnd(uint8_t* data, int offset) {
|
|
data[offset + -0xf] = 3;
|
|
}
|
|
} // namespace jak3
|