#include #include #include "game/overlord/srpc.h" #include "ssound.h" #include "common/util/Assert.h" #include "game/sound/sndshim.h" using namespace iop; Sound gSounds[64]; Curve gCurve[8]; // TODO verify count VolumePair gPanTable[361]; Vec3w gEarTrans; Vec3w gCamTrans; s32 gCamAngle; s32 gMusicVol = 0x400; s32 gMusicFade = 0; s32 gMusicFadeDir = 0; u32 gStreamSRAM = 0; u32 gTrapSRAM = 0; s32 gSema; static u32 sLastTick; static s32 sqrt_table[256] = { 0, 4096, 5793, 7094, 8192, 9159, 10033, 10837, 11585, 12288, 12953, 13585, 14189, 14768, 15326, 15864, 16384, 16888, 17378, 17854, 18318, 18770, 19212, 19644, 20066, 20480, 20886, 21283, 21674, 22058, 22435, 22806, 23170, 23530, 23884, 24232, 24576, 24915, 25249, 25580, 25905, 26227, 26545, 26859, 27170, 27477, 27780, 28081, 28378, 28672, 28963, 29251, 29537, 29819, 30099, 30377, 30652, 30924, 31194, 31462, 31727, 31991, 32252, 32511, 32768, 33023, 33276, 33527, 33776, 34024, 34270, 34514, 34756, 34996, 35235, 35472, 35708, 35942, 36175, 36406, 36636, 36864, 37091, 37316, 37540, 37763, 37985, 38205, 38424, 38642, 38858, 39073, 39287, 39500, 39712, 39923, 40132, 40341, 40548, 40755, 40960, 41164, 41368, 41570, 41771, 41972, 42171, 42369, 42567, 42763, 42959, 43154, 43348, 43541, 43733, 43925, 44115, 44305, 44494, 44682, 44869, 45056, 45242, 45427, 45611, 45795, 45977, 46160, 46341, 46522, 46702, 46881, 47059, 47237, 47415, 47591, 47767, 47942, 48117, 48291, 48465, 48637, 48809, 48981, 49152, 49322, 49492, 49661, 49830, 49998, 50166, 50332, 50499, 50665, 50830, 50995, 51159, 51323, 51486, 51649, 51811, 51972, 52134, 52294, 52454, 52614, 52773, 52932, 53090, 53248, 53405, 53562, 53719, 53874, 54030, 54185, 54340, 54494, 54647, 54801, 54954, 55106, 55258, 55410, 55561, 55712, 55862, 56012, 56162, 56311, 56459, 56608, 56756, 56903, 57051, 57198, 57344, 57490, 57636, 57781, 57926, 58071, 58215, 58359, 58503, 58646, 58789, 58931, 59073, 59215, 59357, 59498, 59639, 59779, 59919, 60059, 60199, 60338, 60477, 60615, 60753, 60891, 61029, 61166, 61303, 61440, 61576, 61712, 61848, 61984, 62119, 62254, 62388, 62523, 62657, 62790, 62924, 63057, 63190, 63323, 63455, 63587, 63719, 63850, 63982, 64113, 64243, 64374, 64504, 64634, 64763, 64893, 65022, 65151, 65279, 65408, }; static s32 atan_table[257] = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, 44, 45, }; void CatalogSRAM() {} static void* SndMemAlloc(); static void SndMemFree(void* ptr); void InitSound_Overlord() { for (auto& s : gSounds) { s.id = 0; } SetCurve(1, 0, 0); SetCurve(2, 0x1000, 0); SetCurve(3, 0, 0x1000); SetCurve(4, 0x800, 0); SetCurve(5, 0x800, 0x800); SetCurve(6, -0x1000, 0); SetCurve(6, -0x800, 0); snd_StartSoundSystem(); snd_RegisterIOPMemAllocator(SndMemAlloc, SndMemFree); snd_LockVoiceAllocator(1); u32 voice = snd_ExternVoiceVoiceAlloc(2, 0x7f); snd_UnlockVoiceAllocator(); // The voice allocator returns a number in the range 0-47 where voices // 0-23 are on SPU Core 0 and 24-47 are on core 2. // For some reason we convert it to this format where 0-47 alternate core every step. voice = voice / 24 + ((voice % 24) * 2); // Allocate SPU RAM for our streams. // (Which we don't need on PC) gStreamSRAM = snd_SRAMMalloc(0xc030); gTrapSRAM = gStreamSRAM + 0xC000; snd_SetMixerMode(0, 0); for (int i = 0; i < 8; i++) { snd_SetGroupVoiceRange(i, 0x10, 0x2f); } snd_SetGroupVoiceRange(1, 0, 0xf); snd_SetGroupVoiceRange(2, 0, 0xf); snd_SetReverbDepth(SND_CORE_0 | SND_CORE_1, 0, 0); snd_SetReverbType(SND_CORE_0, SD_REV_MODE_OFF); snd_SetReverbType(SND_CORE_1, SD_REV_MODE_OFF); CatalogSRAM(); for (int i = 0; i < 91; i++) { s16 opposing_front = static_cast(((i * 0x33ff) / 0x5a) + 0xc00); s16 rear_right = static_cast(((i * -0x2800) / 0x5a) + 0x3400); s16 rear_left = static_cast(((i * -0xbff) / 0x5a) + 0x3fff); gPanTable[90 - i].left = 0x3FFF; gPanTable[180 - i].left = opposing_front; gPanTable[270 - i].left = rear_right; gPanTable[360 - i].left = rear_left; gPanTable[i].right = opposing_front; gPanTable[90 + i].right = 0x3FFF; gPanTable[180 + i].right = rear_left; gPanTable[270 + i].right = rear_right; } snd_SetPanTable((s16*)gPanTable); snd_SetPlayBackMode(2); SemaParam sema; sema.attr = 1; sema.init_count = 1; sema.max_count = 1; sema.option = 0; gSema = CreateSema(&sema); if (gSema < 0) { while (true) ; } } Sound* LookupSound(s32 id) { if (id == 0) { return nullptr; } for (auto& s : gSounds) { if (s.id == id) { s32 sndid = snd_SoundIsStillPlaying(s.sound_handle); s.sound_handle = sndid; if (sndid == 0) { s.id = 0; return nullptr; } return &s; } } return nullptr; } void CleanSounds() { for (auto& s : gSounds) { if (s.id != 0) { s32 sndid = snd_SoundIsStillPlaying(s.sound_handle); s.sound_handle = sndid; if (sndid == 0) { s.id = 0; } } } } void KillSoundsInGroup(u8 group) { for (auto& s : gSounds) { if (s.id != 0) { s32 sndid = snd_SoundIsStillPlaying(s.sound_handle); s.sound_handle = sndid; if (sndid == 0) { s.id = 0; } else if (s.params.group & group) { snd_StopSound(s.sound_handle); s.id = 0; } } } } Sound* AllocateSound() { for (auto& s : gSounds) { if (s.id == 0) { return &s; } } CleanSounds(); for (auto& s : gSounds) { if (s.id == 0) { return &s; } } return nullptr; } s32 CalculateFallofVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 fo_max) { if (fo_curve == 0) { return 0; } s32 xdiff = gEarTrans.x - pos->x; s32 ydiff = gEarTrans.y - pos->y; s32 zdiff = gEarTrans.z - pos->z; if (xdiff < 0) { xdiff = pos->x - gEarTrans.x; } if (ydiff < 0) { ydiff = pos->y - gEarTrans.y; } if (zdiff < 0) { zdiff = pos->z - gEarTrans.z; } s32 min = fo_min << 8; s32 max = fo_max << 8; if (max < xdiff) { return 0; } if (max < ydiff) { return 0; } if (max < zdiff) { return 0; } while (max > 0x7FFF) { max >>= 1; min >>= 1; xdiff >>= 1; ydiff >>= 1; zdiff >>= 1; } u32 distance = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; if (distance != 0) { s32 steps = 0; while ((distance & 0xc0000000) == 0) { distance <<= 2; steps++; } distance = sqrt_table[distance >> 24] >> steps; } else { distance = 0; } if (distance <= (u32)min) { return volume; } if (distance >= (u32)max) { return 0; } s32 start = distance - min; s32 end = max - min; while (start > 0xFFFF) { start >>= 1; end >>= 1; } s32 v13 = (start << 16) / end; if (v13 == 0x10000) { return volume; } s32 factor = ((gCurve[fo_curve].unk4 << 16) + gCurve[fo_curve].unk3 * v13 + gCurve[fo_curve].unk2 * ((v13 * v13) >> 16) + gCurve[fo_curve].unk1 * (((((v13 * v13) >> 16) * v13) >> 16) >> 16)) >> 12; if (factor > 0x10000) { factor = 0x10000; } return (factor * volume) >> 16; } s32 CalculateAngle(Vec3w* trans) { s32 diffX = gCamTrans.x - trans->x; s32 diffZ = gCamTrans.z - trans->z; s32 lookupX = diffX; s32 lookupZ = diffZ; if (diffX < 0) { lookupX = trans->x - gCamTrans.x; } if (diffZ < 0) { lookupZ = trans->z - gCamTrans.z; } if (lookupX == 0 && lookupZ == 0) { return 0; } s32 angle; if (lookupZ >= lookupX) { angle = atan_table[(lookupX << 8) / lookupZ]; if (diffZ >= 0) { if (diffX < 0) { angle = 360 - angle; } } else if (diffX >= 0) { angle = 180 - angle; } else { angle += 180; } } else { angle = atan_table[(lookupZ << 8) / lookupX]; if (diffX >= 0) { if (diffZ >= 0) { angle = 90 - angle; } else { angle = angle + 90; } } else if (diffZ >= 0) { angle = angle + 270; } else { angle = 270 - angle; } } return (angle - gCamAngle + 720) % 360; } s32 GetVolume(Sound* sound) { return CalculateFallofVolume(&sound->params.trans, sound->params.volume, sound->params.fo_curve, sound->params.fo_min, sound->params.fo_max); } s32 GetPan(Sound* sound) { return CalculateAngle(&sound->params.trans); } static void UpdateLocation(Sound* sound) { if (sound->id == 0) { return; } if ((sound->bank_entry->fallof_params >> 28) == 0) { return; } s32 id = snd_SoundIsStillPlaying(sound->sound_handle); if (id == 0) { sound->id = 0; return; } s32 volume = GetVolume(sound); if (volume == 0) { snd_StopSound(sound->sound_handle); } else { s32 pan = GetPan(sound); snd_SetSoundVolPan(id, volume, pan); } } static void UpdateAutoVol(Sound* sound, s32 ticks) { if (ticks < sound->auto_time) { s32 nvol = sound->new_volume; if (nvol == -4) { nvol = 0; } s32 step = (nvol - sound->params.volume) * ticks; step /= sound->auto_time; if (step >= 0) { if (step == 0) { step = 1; } sound->params.volume += step; if (sound->new_volume < sound->params.volume) { sound->params.volume = sound->new_volume; } } else { sound->params.volume += step; if (sound->new_volume > sound->params.volume) { sound->params.volume = sound->new_volume; } } sound->auto_time -= ticks; return; } if (sound->new_volume == -4) { snd_StopSound(sound->sound_handle); sound->id = 0; } else { sound->params.volume = sound->new_volume; } sound->auto_time = 0; } void UpdateVolume(Sound* sound) { s32 id = snd_SoundIsStillPlaying(sound->sound_handle); sound->sound_handle = id; if (sound->sound_handle == 0) { sound->id = 0; } else { s32 volume = GetVolume(sound); snd_SetSoundVolPan(id, volume, -2); } } void SetEarTrans(Vec3w* ear_trans, Vec3w* cam_trans, s32 cam_angle) { s32 tick = snd_GetTick(); u32 delta = tick - sLastTick; sLastTick = tick; gEarTrans = *ear_trans; gCamTrans = *cam_trans; gCamAngle = cam_angle; for (auto& s : gSounds) { if (s.id != 0 && s.is_music == 0) { if (s.auto_time != 0) { UpdateAutoVol(&s, delta); } UpdateLocation(&s); } } // TODO SetVAGVol(); } void PrintActiveSounds() { char string[64]; for (auto& s : gSounds) { if (s.id != 0 && s.is_music == 0) { u32 len = strlen(s.bank_entry->name); if (len > 16) { len = 16; } s32 volume = GetVolume(&s); sprintf(string, " : Vol %d", volume); memcpy(string, s.bank_entry->name, len); printf("%s\n", string); } } } void SetCurve(s32 curve, s32 fallof, s32 ease) { gCurve[curve].unk1 = ease << 1; gCurve[curve].unk2 = fallof + ease * -3; gCurve[curve].unk3 = (ease - fallof) + -0x1000; gCurve[curve].unk4 = 0x1000; } void SetMusicVol() { s32 volume = (gMusicVol * gMusicFade >> 0x10) * gMusicTweak >> 7; snd_SetMasterVolume(1, volume); snd_SetMasterVolume(2, volume); } // Do we even need/want these // TODO void SetBufferMem() {} // TODO void ReleaseBufferMem() {} static void* SndMemAlloc() { return nullptr; } static void SndMemFree(void* /*ptr*/) {}