diff --git a/README.md b/README.md index bead4926..467bf59c 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ This repo contains a work-in-progress decompilation of Diddy Kong Racing for the All versions are supported, and the US 1.0 version (SHA1 = 0cb115d8716dbbc2922fda38e533b9fe63bb9670) of the game is the default if not specified. -As of May 23, 2025, this is our current score: +As of May 26, 2025, this is our current score:     Decomp progress: 88.37% -    Documentation progress: 56.99% +    Documentation progress: 58.39% --- @@ -117,30 +117,30 @@ s32 is_drumstick_unlocked(void) { ``` -As of May 23, 2025, this is our current score: +As of May 26, 2025, this is our current score: ``` - ===================================================================== - ADVENTURE ONE (ASM -> C Decompilation) - --------------- 88.37% Complete (89.33% NON_MATCHING) --------------- - # Decompiled functions: 1900 - # GLOBAL_ASM remaining: 51 - # NON_MATCHING functions: 5 - # NON_EQUIVALENT WIP functions: 15 - ---------------------------- Game Status ---------------------------- - Balloons: 41/47, Keys: 4/4, Trophies: 4/5 - T.T. Amulets: 4/4, Wizpig Amulets: 4/4 - --------------------------------------------------------------------- - We are racing in Spaceport Alpha. (Lap 1/3) - ===================================================================== - ADVENTURE TWO (Cleanup & Documentation) - -------------------------- 56.99% Complete -------------------------- - # Documented functions: 1181 - # Undocumented remaining: 473 - ---------------------------- Game Status ---------------------------- - Balloons: 27/47, Keys: 3/4, Trophies: 2/5 - T.T. Amulets: 3/4, Wizpig Amulets: 2/4 - --------------------------------------------------------------------- - We are collecting silver coins in Crescent Island. (5/8 silver coins) - ===================================================================== + =================================================================== + ADVENTURE ONE (ASM -> C Decompilation) + -------------- 88.37% Complete (89.33% NON_MATCHING) -------------- + # Decompiled functions: 1900 + # GLOBAL_ASM remaining: 51 + # NON_MATCHING functions: 5 + # NON_EQUIVALENT WIP functions: 15 + --------------------------- Game Status --------------------------- + Balloons: 41/47, Keys: 4/4, Trophies: 4/5 + T.T. Amulets: 4/4, Wizpig Amulets: 4/4 + ------------------------------------------------------------------- + We are racing in Spaceport Alpha. (Lap 1/3) + =================================================================== + ADVENTURE TWO (Cleanup & Documentation) + ------------------------- 58.39% Complete ------------------------- + # Documented functions: 1189 + # Undocumented remaining: 465 + --------------------------- Game Status --------------------------- + Balloons: 28/47, Keys: 3/4, Trophies: 2/5 + T.T. Amulets: 3/4, Wizpig Amulets: 2/4 + ------------------------------------------------------------------- + We are collecting silver coins in Pirate Lagoon. (4/8 silver coins) + =================================================================== ``` diff --git a/src/audio_spatial.c b/src/audio_spatial.c index e5a38d26..1c46b696 100644 --- a/src/audio_spatial.c +++ b/src/audio_spatial.c @@ -412,7 +412,7 @@ void audspat_update_all(Object **objList, s32 numObjects, s32 updateRate) { // Update vehicle sounds if (numObjects != 0) { - func_80006FC8(objList, numObjects, cameras, numCameras, updateRate); + racer_sound_update_all(objList, numObjects, cameras, numCameras, updateRate); } } diff --git a/src/audio_spatial.h b/src/audio_spatial.h index 17c8649b..820e35e8 100644 --- a/src/audio_spatial.h +++ b/src/audio_spatial.h @@ -69,17 +69,14 @@ void audspat_line_add_vertex(u8 type, u16 soundBite, f32 x, f32 y, f32 z, u8 arg u8 argA, u8 lineID, u8 vertexIndex); s32 audspat_line_validate(u8 lineID); void audspat_debug_render_line(Gfx **dList, Vertex **verts, Triangle **tris, f32 coords[6], u8 red, u8 green, u8 blue); -void func_80006BFC(Object *obj, Camera *camera, Object *obj2, s32 updateRate); void audspat_point_set_position(AudioPoint *audioPoint, f32 x, f32 y, f32 z); s32 audspat_reverb_validate(u8 reverbLineID); void audspat_init(void); void audspat_reverb_add_vertex(f32, f32, f32, u8, u8, u8); void audspat_calculate_echo(SoundHandle soundHandle, f32 x, f32 y, f32 z); - s32 audspat_distance_to_segment(f32 inX, f32 inY, f32 inZ, f32 coords[6], f32 *outX, f32 *outY, f32 *outZ); void audspat_reset(void); -void audspat_update_all(Object **objList, s32 numObjects, s32 updateRate); // Non Matching -void func_80006FC8(Object **objs, s32 numRacers, Camera *camera, u8 arg3, s32 updateRate); // Non Matching +void audspat_update_all(Object **objList, s32 numObjects, s32 updateRate); u8 audspat_reverb_get_strength_at_point(ReverbLine *, f32, f32, f32); #endif diff --git a/src/audio_vehicle.c b/src/audio_vehicle.c index 6f267553..2f5b14a7 100644 --- a/src/audio_vehicle.c +++ b/src/audio_vehicle.c @@ -15,105 +15,123 @@ /************ .data ************/ u8 gVehicleSounds = TRUE; -s32 D_800DC6D4 = 0; // Currently unknown, might be a different type. +s32 gBackgroundSoundSwapTimer = 0; /*******************************/ /************ .bss ************/ -VehicleSoundData *D_80119C30[2]; +VehicleSoundData *gBackgroundRacerSounds[2]; VehicleSoundData *gRacerSound; Object_Racer *gSoundRacerObj; /******************************/ +/** + * Loads the vehicle sound asset for a given character. + * Allocates and initializes a VehicleSoundData structure by copying data from the corresponding asset. + * Sets the initial pitch and volume values for the engine sound. + */ VehicleSoundData *racer_sound_init(s32 characterId, s32 vehicleId) { s32 unused[2]; s32 i; u8 *ptr; VehicleSoundData *soundData; - s32 l; - s32 *addrPtr; - unkAudioAsset *asset4C; - s32 s1; + u32 l; + s32 *table; + VehicleSoundAsset *asset; + s32 assetOffset; u16 j; - f32 tmp; + f32 interpFrac; u16 v1; - static s32 D_800DC6D8 = TRUE; + static s32 resetAmbient = TRUE; + // Unclear why this compares with 11, since we only have 10 characters. if (characterId >= 11) { characterId = 11; } - if (D_800DC6D8) { - for (i = 0; i < 2; i++) { - D_80119C30[i] = NULL; + // It's unclear why we reset these pointers here — they should already be null initially. + if (resetAmbient) { + for (i = 0; i < ARRAY_COUNT(gBackgroundRacerSounds); i++) { + gBackgroundRacerSounds[i] = NULL; } - D_800DC6D8 = FALSE; + resetAmbient = FALSE; } - addrPtr = (s32 *) load_asset_section_from_rom(ASSET_AUDIO_TABLE); - s1 = addrPtr[ASSET_AUDIO_7] + (vehicleId * 10 + characterId) * sizeof(unkAudioAsset); - asset4C = (unkAudioAsset *) mempool_alloc_safe(sizeof(unkAudioAsset), COLOUR_TAG_CYAN); - load_asset_to_address(ASSET_AUDIO, (u32) asset4C, s1, sizeof(unkAudioAsset)); + // Load the sound asset. + // There are 30 total assets (10 characters × 3 vehicle types: car, plane, hovercraft). + // There is no type check for vehicleId, so passing an unsupported type (e.g. VEHICLE_LOOPDELOOP) + // will cause out-of-bounds access and undefined behavior. + table = (s32 *) load_asset_section_from_rom(ASSET_AUDIO_TABLE); + assetOffset = table[ASSET_AUDIO_7] + (vehicleId * 10 + characterId) * sizeof(VehicleSoundAsset); + asset = (VehicleSoundAsset *) mempool_alloc_safe(sizeof(VehicleSoundAsset), COLOUR_TAG_CYAN); + load_asset_to_address(ASSET_AUDIO, (u32) asset, assetOffset, sizeof(VehicleSoundAsset)); soundData = (VehicleSoundData *) mempool_alloc_safe(sizeof(VehicleSoundData), COLOUR_TAG_CYAN); + // Zero-initialize the structure manually. + // (Technically memset is available in symbols and could be used.) ptr = (u8 *) soundData; for (l = 0; l < sizeof(VehicleSoundData); l++) { *ptr++ = 0; } - soundData->unk36 = asset4C->unk36; - soundData->unk37 = asset4C->unk37; - soundData->unk38 = asset4C->unk38; - soundData->unk39 = asset4C->unk39; - soundData->unk64 = asset4C->unk3A; + // Copy fields from the asset into the sound data structure. + soundData->engineIdleSound = asset->engineIdleSound; + soundData->engineIdleMaxVolume = asset->engineIdleMaxVolume; + soundData->engineIdleMaxPitch = asset->engineIdleMaxPitch; + soundData->engineIdleMinPitch = asset->engineIdleMinPitch; + soundData->unk64_unused = asset->unk3A_unused; - soundData->throttlePitchCeil = asset4C->unk46 / 10000.0f; - soundData->throttlePitchVel = asset4C->unk3E / 10000.0f; - soundData->throttlePitchDecay = asset4C->unk40 / 10000.0f; - soundData->unkC0 = asset4C->unk42 / 10000.0f; - soundData->unkC4 = asset4C->unk44 / 10000.0f; - soundData->unkBC = asset4C->unk3C / 10000.0f; - soundData->unkB8 = asset4C->unk3B; - soundData->unkCC = asset4C->unk48 / 10000.0f; - soundData->brakeSound = FALSE; + soundData->thrustPitchMax = asset->thrustPitchMax / 10000.0f; + soundData->thrustPitchVel = asset->thrustPitchVel / 10000.0f; + soundData->thrustPitchDecay = asset->thrustPitchDecay / 10000.0f; + soundData->rollAnglePitchScale = asset->rollAnglePitchScale / 10000.0f; + soundData->pitchAnglePitchScale = asset->pitchAnglePitchScale / 10000.0f; + soundData->pitchLateralSpeedScale = asset->pitchLateralSpeedScale / 10000.0f; + soundData->unkB8_unused = asset->unk3B_unused; + soundData->thrustPitchSpeedScale = asset->thrustPitchSpeedScale / 10000.0f; + soundData->spinoutSoundOn = FALSE; for (i = 0; i < 2; i++) { - soundData->unk0[i] = asset4C->unk0[i]; + soundData->soundId[i] = asset->soundId[i]; for (l = 0; l < 5; l++) { - soundData->unk4[i][l] = asset4C->unk4[i][l]; - soundData->unk18[i][l] = asset4C->unk18[i][l]; - soundData->unkE[i][l] = asset4C->unkE[i][l]; - soundData->unk2C[i][l] = asset4C->unk2C[i][l]; + soundData->intensityLevelsForPitch[i][l] = asset->intensityLevelsForPitch[i][l]; + soundData->pitchLevels[i][l] = asset->pitchLevels[i][l]; + soundData->intensityLevelsForVolume[i][l] = asset->intensityLevelsForVolume[i][l]; + soundData->volumeLevels[i][l] = asset->volumeLevels[i][l]; } } - soundData->unk74 = 0; - soundData->unk6C[0] = 0.0f; - soundData->basePitch = asset4C->unk4A / 100.0f; + soundData->backgroundState = VEHICLE_BACKGROUND_STOPPED; + soundData->prevDistance[0] = 0.0f; + soundData->planeHovercraftBasePitch = asset->planeHovercraftBasePitch / 100.0f; + // For cars, initial pitch and volume are taken from the first level of the engine intensity-to-sound tables. + // For planes and hovercrafts, the pitch starts at a fixed base value from the asset. if (vehicleId == VEHICLE_CAR) { - soundData->unk54[0] = soundData->unk2C[0][0]; - soundData->unk5C[0] = soundData->unk18[0][0] / 10000.0f; - soundData->unk54[1] = soundData->unk2C[1][0]; - soundData->unk5C[1] = soundData->unk18[1][0] / 10000.0f; + soundData->baseVolume[0] = soundData->volumeLevels[0][0]; + soundData->basePitch[0] = soundData->pitchLevels[0][0] / 10000.0f; + soundData->baseVolume[1] = soundData->volumeLevels[1][0]; + soundData->basePitch[1] = soundData->pitchLevels[1][0] / 10000.0f; } else { - soundData->unk5C[0] = soundData->basePitch; - v1 = soundData->unk5C[0] * 10000.0f; + soundData->basePitch[0] = soundData->planeHovercraftBasePitch; + v1 = soundData->basePitch[0] * 10000.0f; - for (j = 0; v1 >= soundData->unk18[0][j] && j < 4; j++) {} + for (j = 0; v1 >= soundData->pitchLevels[0][j] && j < 4; j++) {} j--; - tmp = (f32) (v1 - soundData->unk18[0][j]) / (soundData->unk18[0][j + 1] - soundData->unk18[0][j]); - soundData->unk54[0] = soundData->unk2C[0][j] + (soundData->unk2C[0][j + 1] - soundData->unk2C[0][j]) * tmp; + interpFrac = (f32) (v1 - soundData->pitchLevels[0][j]) / + (soundData->pitchLevels[0][j + 1] - soundData->pitchLevels[0][j]); + soundData->baseVolume[0] = soundData->volumeLevels[0][j] + + (soundData->volumeLevels[0][j + 1] - soundData->volumeLevels[0][j]) * interpFrac; } - mempool_free(addrPtr); - mempool_free(asset4C); + mempool_free(table); + mempool_free(asset); return soundData; } @@ -123,18 +141,18 @@ VehicleSoundData *racer_sound_init(s32 characterId, s32 vehicleId) { * Check which vehicle is being used, update the position of the audio, * then call a function to handle that particular vehicles audio. */ -void racer_sound_update(Object *obj, u32 buttonsPressed, u32 buttonsHeld, s32 updateRate) { +void racer_sound_update(Object *obj, u32 buttonsPressed, u32 buttonsHeld, s32 ticksDelta) { if (gVehicleSounds) { gSoundRacerObj = &obj->unk64->racer; - gRacerSound = (VehicleSoundData *) gSoundRacerObj->vehicleSound; + gRacerSound = gSoundRacerObj->vehicleSound; if (gRacerSound != NULL) { - if (get_race_countdown()) { + if (get_race_countdown() != 0) { if (gSoundRacerObj->playerIndex != PLAYER_COMPUTER) { buttonsHeld = input_held(gSoundRacerObj->playerIndex); buttonsPressed = input_pressed(gSoundRacerObj->playerIndex); } } - if (gRacerSound->unk0[0] == 0) { + if (gRacerSound->soundId[0] == 0) { gRacerSound->racerPos.x = -32000.0f; gRacerSound->racerPos.y = -32000.0f; gRacerSound->racerPos.z = -32000.0f; @@ -144,13 +162,13 @@ void racer_sound_update(Object *obj, u32 buttonsPressed, u32 buttonsHeld, s32 up gRacerSound->racerPos.z = obj->segment.trans.z_position; switch (gSoundRacerObj->vehicleIDPrev) { case VEHICLE_HOVERCRAFT: - racer_sound_hovercraft(obj, buttonsPressed, buttonsHeld, updateRate); + racer_sound_hovercraft(obj, buttonsPressed, buttonsHeld, ticksDelta); break; case VEHICLE_PLANE: - func_800063EC(obj, buttonsPressed, buttonsHeld, updateRate); + racer_sound_plane(obj, buttonsPressed, buttonsHeld, ticksDelta); break; default: - func_80005254(obj, buttonsPressed, buttonsHeld, updateRate); + racer_sound_car(obj, buttonsPressed, buttonsHeld, ticksDelta); break; } } @@ -158,159 +176,197 @@ void racer_sound_update(Object *obj, u32 buttonsPressed, u32 buttonsHeld, s32 up } } -void func_80005254(Object *obj, u32 buttonsPressed, u32 buttonsHeld, s32 updateRate) { - f32 temp_f14; - f32 temp_f16; - f32 temp_f18; - u8 temp_f4; - f32 var_f0; - s32 var_s0; - s32 innerLoop; - f32 var_f20; - s32 outerLoop; - f32 var_f14; - f32 var_f12; - f32 var_f2; - f32 sp6C; - s32 var_v1_3; +/** + * Calculates car engine sound pitch and volume, as well as the brake sound pitch and volume. + * Engine sound depends on speed, number of bananas collected, acceleration button state, drifting, and whether the car + * is airborne. + */ +void racer_sound_car(Object *obj, u32 buttonsPressed, u32 buttonsHeld, s32 ticksDelta) { + f32 interpFrac; + f32 pitch1; + f32 pitch2; + u8 targetVolume; + f32 speed; + s32 intensity; + s32 j; + f32 absVelocity; + s32 i; + f32 deltaVolume; + f32 deltaPitch; + f32 targetPitch; + f32 brakePitch; + s32 bananas; if (gSoundRacerObj->unk1FB != 0) { - var_f0 = 12.0f; + speed = 12.0f; } else { - var_f0 = gSoundRacerObj->velocity; + speed = gSoundRacerObj->velocity; } - if (var_f0 < 0.0f) { - var_f0 = -var_f0; + if (speed < 0.0f) { + speed = -speed; } - var_s0 = (var_f0 / 16) * 100; - var_s0 += 5; - if (var_s0 > 100) { - var_s0 = 100; + + // Convert speed to engine intensity ranging from 5 to 100, with 16 being maximum speed + intensity = (speed / 16) * 100; + intensity += 5; + if (intensity > 100) { + intensity = 100; } - for (outerLoop = 0; outerLoop < 1; outerLoop++) { - if ((gRacerSound->unk0[outerLoop]) != 0) { - innerLoop = 0; - while ((var_s0 < gRacerSound->unkE[outerLoop][innerLoop] || - var_s0 > gRacerSound->unkE[outerLoop][innerLoop + 1]) && - innerLoop < 4) { - innerLoop++; + + // Only process the main engine sound; the secondary sound uses fixed pitch and volume + for (i = 0; i < 1; i++) { + if ((gRacerSound->soundId[i]) != 0) { + // Calculate volume by interpolating between control points based on intensity + j = 0; + while ((intensity < gRacerSound->intensityLevelsForVolume[i][j] || + intensity > gRacerSound->intensityLevelsForVolume[i][j + 1]) && + j < 4) { + j++; + } + interpFrac = + (intensity - gRacerSound->intensityLevelsForVolume[i][j]) / + ((f32) (gRacerSound->intensityLevelsForVolume[i][j + 1] - gRacerSound->intensityLevelsForVolume[i][j])); + targetVolume = gRacerSound->volumeLevels[i][j] + + (gRacerSound->volumeLevels[i][j + 1] - gRacerSound->volumeLevels[i][j]) * interpFrac; + + // Calculate base pitch similarly by interpolating between control points + j = 0; + while ((intensity < gRacerSound->intensityLevelsForPitch[i][j] || + intensity > gRacerSound->intensityLevelsForPitch[i][j + 1]) && + j < 4) { + j++; } - temp_f14 = (var_s0 - gRacerSound->unkE[outerLoop][innerLoop]) / - ((f32) (gRacerSound->unkE[outerLoop][innerLoop + 1] - gRacerSound->unkE[outerLoop][innerLoop])); - temp_f4 = - gRacerSound->unk2C[outerLoop][innerLoop] + - (gRacerSound->unk2C[outerLoop][innerLoop + 1] - gRacerSound->unk2C[outerLoop][innerLoop]) * temp_f14; + interpFrac = + (intensity - gRacerSound->intensityLevelsForPitch[i][j]) / + ((f32) (gRacerSound->intensityLevelsForPitch[i][j + 1] - gRacerSound->intensityLevelsForPitch[i][j])); + pitch1 = gRacerSound->pitchLevels[i][j] / 10000.0f; + pitch2 = gRacerSound->pitchLevels[i][j + 1] / 10000.0f; - innerLoop = 0; - while ((var_s0 < gRacerSound->unk4[outerLoop][innerLoop] || - var_s0 > gRacerSound->unk4[outerLoop][innerLoop + 1]) && - innerLoop < 4) { - innerLoop++; - } + // Apply pitch modifiers - temp_f14 = (var_s0 - gRacerSound->unk4[outerLoop][innerLoop]) / - ((f32) (gRacerSound->unk4[outerLoop][innerLoop + 1] - gRacerSound->unk4[outerLoop][innerLoop])); - temp_f16 = gRacerSound->unk18[outerLoop][innerLoop] / 10000.0f; - temp_f18 = gRacerSound->unk18[outerLoop][innerLoop + 1] / 10000.0f; - if (var_s0 > 50 && gSoundRacerObj->bananas != 0) { + // Each banana adds 0.05 to the pitch (up to 0.5), with smooth transitions, + // but only if engine intensity is above 50%. Below 50%, this bonus fades out smoothly. + if (intensity > 50 && gSoundRacerObj->bananas != 0) { if (gSoundRacerObj->bananas <= 10) { - var_v1_3 = gSoundRacerObj->bananas; + bananas = gSoundRacerObj->bananas; } else { - var_v1_3 = 10; + bananas = 10; } - if (gRacerSound->bananaPitch < (0.05 * var_v1_3)) { - gRacerSound->bananaPitch += ((0.05 * var_v1_3) / (var_v1_3 * 64)); - } else if (gRacerSound->bananaPitch > (0.05 * var_v1_3)) { - gRacerSound->bananaPitch = (0.05 * var_v1_3); + if (gRacerSound->bananaPitch < 0.05 * bananas) { + gRacerSound->bananaPitch += (0.05 * bananas) / (bananas * 64); + } else if (gRacerSound->bananaPitch > 0.05 * bananas) { + gRacerSound->bananaPitch = 0.05 * bananas; } - var_f2 = ((temp_f18 - temp_f16) * temp_f14) + temp_f16 + gRacerSound->bananaPitch; + targetPitch = ((pitch2 - pitch1) * interpFrac) + pitch1 + gRacerSound->bananaPitch; } else { gRacerSound->bananaPitch *= 0.95; - var_f2 = ((temp_f18 - temp_f16) * temp_f14) + temp_f16 + gRacerSound->bananaPitch; + targetPitch = ((pitch2 - pitch1) * interpFrac) + pitch1 + gRacerSound->bananaPitch; } + + // Add 0.13 pitch boost when drifting, with smooth increase and fast decay when drifting stops if (gSoundRacerObj->drift_direction != 0) { - gRacerSound->unk40 += ((0.13 - gRacerSound->unk40) / 8); + gRacerSound->driftPitch += (0.13 - gRacerSound->driftPitch) / 8; } else { - gRacerSound->unk40 /= 4; + gRacerSound->driftPitch /= 4; } - var_f2 += gRacerSound->unk40; - if ((gSoundRacerObj->groundedWheels == 0) && (gSoundRacerObj->playerIndex != PLAYER_COMPUTER)) { - var_f2 += 0.3; + targetPitch += gRacerSound->driftPitch; + + // Add instant 0.3 pitch boost when the car is in the air (not grounded), but only for player cars + if (gSoundRacerObj->groundedWheels == 0 && (gSoundRacerObj->playerIndex != PLAYER_COMPUTER)) { + targetPitch += 0.3; } - var_f12 = (var_f2 - gRacerSound->unk5C[outerLoop]) / 2; - var_f14 = (temp_f4 - gRacerSound->unk54[outerLoop]) / 2; + + // Smooth pitch and volume changes over two frames to allow jitter effects + deltaPitch = (targetPitch - gRacerSound->basePitch[i]) / 2; + deltaVolume = (targetVolume - gRacerSound->baseVolume[i]) / 2; + + // Add engine jitter effect for player cars to simulate engine vibration + // Max pitch variation ±0.02, volume variation ±5 if (gSoundRacerObj->playerIndex != PLAYER_COMPUTER) { if (get_random_number_from_range(0, 10) < 7) { - gRacerSound->unk90 += get_random_number_from_range(0, 10) - 5; - if (gRacerSound->unk90 > 5) { - gRacerSound->unk90 = 5; - } else if (gRacerSound->unk90 < -5) { - gRacerSound->unk90 = -5; + gRacerSound->engineJitter += get_random_number_from_range(0, 10) - 5; + if (gRacerSound->engineJitter > 5) { + gRacerSound->engineJitter = 5; + } else if (gRacerSound->engineJitter < -5) { + gRacerSound->engineJitter = -5; } } - var_f12 += 0.02 * (gRacerSound->unk90 / 5.0f); - var_f14 += 5.0f * (gRacerSound->unk90 / 5.0f); + deltaPitch += 0.02 * (gRacerSound->engineJitter / 5.0f); + deltaVolume += 5.0f * (gRacerSound->engineJitter / 5.0f); } - if ((buttonsHeld & A_BUTTON) && (gRacerSound->enginePitch < 0.4)) { - gRacerSound->enginePitch += ((f32) updateRate * 0.01); + + // While acceleration button is held, gradually increase pitch boost up to 0.4 (by 0.01 per frame) + if ((buttonsHeld & A_BUTTON) && gRacerSound->enginePitch < 0.4) { + gRacerSound->enginePitch += ((f32) ticksDelta * 0.01); if (gRacerSound->enginePitch > 0.4) { gRacerSound->enginePitch = 0.4f; } } + + // When acceleration is released, decrease pitch boost smoothly (by 0.005 per frame) if (!(buttonsHeld & A_BUTTON) && (gRacerSound->enginePitch > 0.0f)) { - gRacerSound->enginePitch -= ((f32) updateRate * 0.005); + gRacerSound->enginePitch -= ((f32) ticksDelta * 0.005); if (gRacerSound->enginePitch < 0.0f) { gRacerSound->enginePitch = 0.0f; } } - gRacerSound->unk5C[outerLoop] += var_f12; + gRacerSound->basePitch[i] += deltaPitch; if (buttonsHeld & A_BUTTON) { - gRacerSound->unk54[outerLoop] += var_f14; + gRacerSound->baseVolume[i] += deltaVolume; } else { - gRacerSound->unk54[outerLoop] = 35.0f; + // When acceleration isn't pressed, volume stays fixed at 35 regardless of speed + gRacerSound->baseVolume[i] = 35.0f; } } } - if (((gSoundRacerObj->unk10 != 0) || (gSoundRacerObj->unk14 != 0) || !(buttonsHeld & B_BUTTON) || - (gSoundRacerObj->velocity > -0.1) || (gSoundRacerObj->vehicleID == 4)) && - (gRacerSound->unkA8 != 0)) { - sndp_stop(gRacerSound->unkA8); - gRacerSound->unkA8 = 0; - } else if ((buttonsPressed & B_BUTTON) && (gRacerSound->unkA8 == 0) && (gSoundRacerObj->playerIndex >= 0)) { + + // Start or stop the brake sound based on conditions + if ((gSoundRacerObj->unk10 != NULL || gSoundRacerObj->unk14 != NULL || !(buttonsHeld & B_BUTTON) || + gSoundRacerObj->velocity > -0.1 || gSoundRacerObj->vehicleID == VEHICLE_LOOPDELOOP) && + gRacerSound->brakeSound != NULL) { + sndp_stop(gRacerSound->brakeSound); + gRacerSound->brakeSound = NULL; + } else if ((buttonsPressed & B_BUTTON) && gRacerSound->brakeSound == NULL && gSoundRacerObj->playerIndex >= 0) { if (gSoundRacerObj->velocity < 0.0f) { - var_f20 = -gSoundRacerObj->velocity; + absVelocity = -gSoundRacerObj->velocity; } else { - var_f20 = gSoundRacerObj->velocity; + absVelocity = gSoundRacerObj->velocity; } - if (var_f20 > 12.0f) { - var_f20 = 12.0f; + if (absVelocity > 12.0f) { + absVelocity = 12.0f; } - func_80001F14(25, &gRacerSound->unkA8); - sp6C = (((var_f20 * 0.5) / 12.0) + 0.5); - if (gRacerSound->unkA8 != 0) { - sndp_set_param(gRacerSound->unkA8, AL_SNDP_PITCH_EVT, *((u32 *) &sp6C)); + func_80001F14(25, &gRacerSound->brakeSound); + // Brake pitch depends on speed, ranges from 0.5 to 1.0 + brakePitch = absVelocity * 0.5 / 12.0 + 0.5; + if (gRacerSound->brakeSound != NULL) { + sndp_set_param(gRacerSound->brakeSound, AL_SNDP_PITCH_EVT, *((u32 *) &brakePitch)); } - gRacerSound->unkAC = 110; - gRacerSound->unkD0 = 0; + gRacerSound->brakeSoundVolume = 110; + gRacerSound->airTime = 0; } - if (gRacerSound->unkA8 != 0) { + + if (gRacerSound->brakeSound != NULL) { if (gSoundRacerObj->groundedWheels == 0) { - gRacerSound->unkD0 += updateRate; + gRacerSound->airTime += ticksDelta; } else { - gRacerSound->unkD0 = 0; + gRacerSound->airTime = 0; } - if (gRacerSound->unkD0 >= 10) { - sndp_set_param(gRacerSound->unkA8, AL_SNDP_VOL_EVT, 0); + if (gRacerSound->airTime >= 10) { + // Stop brake sound after being airborne for 10 consecutive frames + sndp_set_param(gRacerSound->brakeSound, AL_SNDP_VOL_EVT, 0); } else { - sndp_set_param(gRacerSound->unkA8, AL_SNDP_VOL_EVT, gRacerSound->unkAC << 8); - audspat_calculate_echo(gRacerSound->unkA8, obj->segment.trans.x_position, obj->segment.trans.y_position, - obj->segment.trans.z_position); + sndp_set_param(gRacerSound->brakeSound, AL_SNDP_VOL_EVT, gRacerSound->brakeSoundVolume << 8); + audspat_calculate_echo(gRacerSound->brakeSound, obj->segment.trans.x_position, + obj->segment.trans.y_position, obj->segment.trans.z_position); } } - gRacerSound->unkA0 = var_s0; - if ((buttonsHeld & A_BUTTON) != 0) { - gRacerSound->unk98 = gRacerSound->unk54[0]; + + // Store current engine intensity for later use (e.g. idle sound calculation) + gRacerSound->engine_intensity = intensity; + + if (buttonsHeld & A_BUTTON) { + gRacerSound->unk98_unused = gRacerSound->baseVolume[0]; } } @@ -319,197 +375,239 @@ void func_80005254(Object *obj, u32 buttonsPressed, u32 buttonsHeld, s32 updateR * Uses velocity, banana count and ground contact to decide what pitch to use. * Those values are calculated in this function. */ -void racer_sound_hovercraft(Object *obj, UNUSED u32 buttonsPressed, u32 buttonsHeld, s32 updateRate) { +void racer_sound_hovercraft(Object *obj, UNUSED u32 buttonsPressed, u32 buttonsHeld, s32 tickDelta) { UNUSED s32 pad; - f32 velocity; - f32 new_var; - u16 temp_f10; + f32 speed; + f32 fracPart; + u16 pitchLevel; f32 angleSine; - f32 var_f18; - f32 pitch; - s32 angleDiff; - s32 bananaPitch; - u8 var_t0; + f32 lateralSpeedPitch; + f32 targetPitch; + s32 angle; + s32 bananas; + u8 volume; u8 i; if (get_race_countdown() == 0) { - velocity = sqrtf((obj->segment.x_velocity * obj->segment.x_velocity) + - (obj->segment.z_velocity * obj->segment.z_velocity)); + speed = sqrtf((obj->segment.x_velocity * obj->segment.x_velocity) + + (obj->segment.z_velocity * obj->segment.z_velocity)); } else { - velocity = 0.0f; - } - pitch = gRacerSound->basePitch; - if (buttonsHeld & A_BUTTON) { - gRacerSound->throttlePitch += gRacerSound->throttlePitchVel * updateRate; - if (gRacerSound->throttlePitch > gRacerSound->throttlePitchCeil) { - gRacerSound->throttlePitch = gRacerSound->throttlePitchCeil; - } - } else { - gRacerSound->throttlePitch -= gRacerSound->throttlePitchDecay * updateRate; - } - if (gRacerSound->throttlePitch < 0.0f) { - gRacerSound->throttlePitch = 0.0f; + speed = 0.0f; } - angleDiff = (-gSoundRacerObj->cameraYaw - (gSoundRacerObj->steerVisualRotation & 0xFFFF)) + 0x8000; - WRAP(angleDiff, -0x8000, 0x8000); - angleSine = sins_f(angleDiff); + targetPitch = gRacerSound->planeHovercraftBasePitch; + + // All pitch-related parameters for acceleration are defined in assets, + // unlike cars where they're hardcoded. + if (buttonsHeld & A_BUTTON) { + gRacerSound->thrustPitch += gRacerSound->thrustPitchVel * tickDelta; + if (gRacerSound->thrustPitch > gRacerSound->thrustPitchMax) { + gRacerSound->thrustPitch = gRacerSound->thrustPitchMax; + } + } else { + gRacerSound->thrustPitch -= gRacerSound->thrustPitchDecay * tickDelta; + } + if (gRacerSound->thrustPitch < 0.0f) { + gRacerSound->thrustPitch = 0.0f; + } + + // If the hovercraft is angled relative to the camera view, add pitch offset accordingly. + angle = (-gSoundRacerObj->cameraYaw - (gSoundRacerObj->steerVisualRotation & 0xFFFF)) + 0x8000; + WRAP(angle, -0x8000, 0x8000); + angleSine = sins_f(angle); angleSine = ABSF(angleSine); - if (check_if_showing_cutscene_camera() == FALSE && get_race_countdown() == 0) { - var_f18 = (gRacerSound->unkBC * angleSine * velocity) / 15.0; + if (!check_if_showing_cutscene_camera() && get_race_countdown() == 0) { + lateralSpeedPitch = (gRacerSound->pitchLateralSpeedScale * angleSine * speed) / 15.0; } else { - var_f18 = 0.0f; + lateralSpeedPitch = 0.0f; } - if (race_starting() == FALSE) { - gRacerSound->throttlePitch = 0.0f; + + if (!race_starting()) { + gRacerSound->thrustPitch = 0.0f; } - if (velocity > 10.0) { - velocity -= 10.0; + if (speed > 10.0) { + speed -= 10.0; } else { - velocity = 0.0f; + speed = 0.0f; } + + // Apply pitch bonus from collected bananas: +0.05 per banana. + // Only applies when speed is above 10, i.e. near maximum. + // Otherwise, the bonus fades out gradually. //!@Delta: This entire block is not timing correct. - if (velocity != 0.0 && gSoundRacerObj->bananas != 0) { + if (speed != 0.0 && gSoundRacerObj->bananas != 0) { if (gSoundRacerObj->bananas <= 10) { - bananaPitch = gSoundRacerObj->bananas; + bananas = gSoundRacerObj->bananas; } else { - bananaPitch = 10; + bananas = 10; } - if (gRacerSound->bananaPitch < 0.05 * bananaPitch) { - gRacerSound->bananaPitch += (0.05 * bananaPitch) / (bananaPitch * 64); - } else if (gRacerSound->bananaPitch > 0.05 * bananaPitch) { - gRacerSound->bananaPitch = 0.05 * bananaPitch; + if (gRacerSound->bananaPitch < 0.05 * bananas) { + gRacerSound->bananaPitch += (0.05 * bananas) / (bananas * 64); + } else if (gRacerSound->bananaPitch > 0.05 * bananas) { + gRacerSound->bananaPitch = 0.05 * bananas; } - pitch += gRacerSound->bananaPitch; + targetPitch += gRacerSound->bananaPitch; } else { gRacerSound->bananaPitch *= 0.95; - pitch += gRacerSound->bananaPitch; + targetPitch += gRacerSound->bananaPitch; } - pitch += ((velocity * gRacerSound->unkCC) + var_f18 + gRacerSound->throttlePitch); + + // Additional pitch based on speed, lateral movement, and engine thrust. + targetPitch += speed * gRacerSound->thrustPitchSpeedScale + lateralSpeedPitch + gRacerSound->thrustPitch; + + // Add +0.3 to pitch if the hovercraft is over water (for non-AI players). if (gSoundRacerObj->playerIndex != PLAYER_COMPUTER && gSoundRacerObj->groundedWheels == 0 && gSoundRacerObj->waterTimer < 4) { if (get_race_countdown() == 0) { - pitch += 0.3; + targetPitch += 0.3; } } - gRacerSound->unk5C[0] += ((pitch - gRacerSound->unk5C[0]) / 8); - if (gRacerSound->unk5C[0] > (0x7FFF / 5000.0)) { - gRacerSound->unk5C[0] = (0x7FFF / 5000.0); // 6.5534 + + // Smoothly interpolate pitch and clamp to maximum. + // The max pitch value is 0x7FFF / 5000.0 (~6.5534), but its origin is unclear. + gRacerSound->basePitch[0] += (targetPitch - gRacerSound->basePitch[0]) / 8; + if (gRacerSound->basePitch[0] > (0x7FFF / 5000.0)) { + gRacerSound->basePitch[0] = (0x7FFF / 5000.0); // 6.5534 } - temp_f10 = gRacerSound->unk5C[0] * 10000.0f; - for (i = 0; temp_f10 >= gRacerSound->unk18[0][i] && i < 4; i++) {} + + // Convert pitch to volume by interpolating between control points. + pitchLevel = gRacerSound->basePitch[0] * 10000.0f; + for (i = 0; pitchLevel >= gRacerSound->pitchLevels[0][i] && i < 4; i++) {} if (i == 4) { - var_t0 = gRacerSound->unk2C[0][i]; + volume = gRacerSound->volumeLevels[0][i]; } else { if (i != 0) { i--; } - new_var = - (temp_f10 - gRacerSound->unk18[0][i]) / ((f32) (gRacerSound->unk18[0][i + 1] - gRacerSound->unk18[0][i])); - var_t0 = gRacerSound->unk2C[0][i] + (gRacerSound->unk2C[0][i + 1] - gRacerSound->unk2C[0][i]) * new_var; + fracPart = (pitchLevel - gRacerSound->pitchLevels[0][i]) / + ((f32) (gRacerSound->pitchLevels[0][i + 1] - gRacerSound->pitchLevels[0][i])); + volume = gRacerSound->volumeLevels[0][i] + + (gRacerSound->volumeLevels[0][i + 1] - gRacerSound->volumeLevels[0][i]) * fracPart; } - gRacerSound->unk54[0] += ((var_t0 - gRacerSound->unk54[0]) / 8); - gRacerSound->unk5C[1] = 1.0f; - gRacerSound->unk54[1] = 0.0f; + gRacerSound->baseVolume[0] += (volume - gRacerSound->baseVolume[0]) / 8; + gRacerSound->basePitch[1] = 1.0f; + gRacerSound->baseVolume[1] = 0.0f; } -void func_800063EC(Object *obj, UNUSED u32 buttonsPressed, u32 buttonsHeld, s32 updateRate) { - f32 var_f18; - f32 sp28; - f32 var_f2; - u16 temp_f10; - f32 temp_f8; - f32 var_f14; +/** + * Sets engine and spinout sound parameters for the plane. + * The engine pitch is influenced by acceleration input, current speed, banana count, and the plane’s orientation. + */ +void racer_sound_plane(Object *obj, UNUSED u32 buttonsPressed, u32 buttonsHeld, s32 tickDelta) { + f32 speed; + f32 xSine; + f32 zSine; + u16 pitchLevel; + f32 interpFrac; + f32 targetPitch; u8 i; - s32 var_a0; - u8 var_t0; + s32 bananas; + u8 volume; f32 temp; f32 temp2; if (get_race_countdown() == 0) { - var_f18 = sqrtf((obj->segment.x_velocity * obj->segment.x_velocity) + - (obj->segment.z_velocity * obj->segment.z_velocity) + - (obj->segment.y_velocity * obj->segment.y_velocity)); + speed = sqrtf((obj->segment.x_velocity * obj->segment.x_velocity) + + (obj->segment.z_velocity * obj->segment.z_velocity) + + (obj->segment.y_velocity * obj->segment.y_velocity)); } else { - var_f18 = 0.0f; + speed = 0.0f; } - if (var_f18 < 2.0f) { - gRacerSound->unk54[0] += ((gRacerSound->unk37 - gRacerSound->unk54[0]) / 8); + + if (speed < 2.0f) { + // If speed is below 2, treat the plane as idle and smoothly blend to the idle engine volume. + gRacerSound->baseVolume[0] += (gRacerSound->engineIdleMaxVolume - gRacerSound->baseVolume[0]) / 8; } else { - temp_f10 = gRacerSound->unk5C[0] * 10000.0f; - for (i = 0; temp_f10 >= gRacerSound->unk18[0][i] && i < 4; i++) {} + // Compute volume based on pitch using linear interpolation between volume control points. + // Note: Uses pitch from the previous frame. + pitchLevel = gRacerSound->basePitch[0] * 10000.0f; + for (i = 0; pitchLevel >= gRacerSound->pitchLevels[0][i] && i < 4; i++) {} if (i == 4) { - var_t0 = gRacerSound->unk2C[0][i]; + volume = gRacerSound->volumeLevels[0][i]; } else { if (i != 0) { i--; } - temp_f8 = (temp_f10 - gRacerSound->unk18[0][i]) / - ((f32) (gRacerSound->unk18[0][i + 1] - gRacerSound->unk18[0][i])); - var_t0 = gRacerSound->unk2C[0][i] + (gRacerSound->unk2C[0][i + 1] - gRacerSound->unk2C[0][i]) * temp_f8; + interpFrac = (pitchLevel - gRacerSound->pitchLevels[0][i]) / + ((f32) (gRacerSound->pitchLevels[0][i + 1] - gRacerSound->pitchLevels[0][i])); + volume = gRacerSound->volumeLevels[0][i] + + (gRacerSound->volumeLevels[0][i + 1] - gRacerSound->volumeLevels[0][i]) * interpFrac; } - gRacerSound->unk54[0] += ((var_t0 - gRacerSound->unk54[0]) / 8); + gRacerSound->baseVolume[0] += ((volume - gRacerSound->baseVolume[0]) / 8); } - var_f14 = gRacerSound->basePitch; + + targetPitch = gRacerSound->planeHovercraftBasePitch; + + // All pitch-related parameters for acceleration are defined in assets, + // unlike cars where they're hardcoded. if (buttonsHeld & A_BUTTON) { - gRacerSound->throttlePitch += gRacerSound->throttlePitchVel * updateRate; - if (gRacerSound->throttlePitchCeil < gRacerSound->throttlePitch) { - gRacerSound->throttlePitch = gRacerSound->throttlePitchCeil; + gRacerSound->thrustPitch += gRacerSound->thrustPitchVel * tickDelta; + if (gRacerSound->thrustPitchMax < gRacerSound->thrustPitch) { + gRacerSound->thrustPitch = gRacerSound->thrustPitchMax; } } else { - gRacerSound->throttlePitch -= gRacerSound->throttlePitchDecay * updateRate; + gRacerSound->thrustPitch -= gRacerSound->thrustPitchDecay * tickDelta; } - if (gRacerSound->throttlePitch < 0) { - gRacerSound->throttlePitch = 0; + if (gRacerSound->thrustPitch < 0) { + gRacerSound->thrustPitch = 0; } - if (race_starting() == 0) { - gRacerSound->throttlePitch = 0; + if (!race_starting()) { + gRacerSound->thrustPitch = 0; } - var_f14 += gRacerSound->throttlePitch; - sp28 = sins_f(obj->segment.trans.rotation.x_rotation); - var_f2 = sins_f(obj->segment.trans.rotation.z_rotation); - temp = gRacerSound->unkC4 * sp28; - temp2 = gRacerSound->unkC0 * var_f2; + targetPitch += gRacerSound->thrustPitch; + + // Add pitch modifiers based on pitch and roll angles of the plane. + xSine = sins_f(obj->segment.trans.rotation.x_rotation); + zSine = sins_f(obj->segment.trans.rotation.z_rotation); + temp = gRacerSound->pitchAnglePitchScale * xSine; + temp2 = gRacerSound->rollAnglePitchScale * zSine; temp2 = ABSF(temp2); - var_f14 += temp + temp2; + targetPitch += temp + temp2; - if (var_f18 > 10.0) { - var_f18 -= 10.0; + // Apply additional pitch if speed exceeds 10. + if (speed > 10.0) { + speed -= 10.0; } else { - var_f18 = 0.0f; + speed = 0.0f; } + targetPitch += speed * gRacerSound->thrustPitchSpeedScale; - var_f14 += var_f18 * gRacerSound->unkCC; - if (var_f18 != 0.0 && gSoundRacerObj->bananas != 0) { + // Apply pitch bonus from collected bananas: +0.05 per banana. + // Only applies when speed is above 10, i.e. near maximum. + // Otherwise, the bonus fades out gradually. + if (speed != 0.0 && gSoundRacerObj->bananas != 0) { if (gSoundRacerObj->bananas <= 10) { - var_a0 = gSoundRacerObj->bananas; + bananas = gSoundRacerObj->bananas; } else { - var_a0 = 10; + bananas = 10; } - if (gRacerSound->bananaPitch < 0.05 * var_a0) { - gRacerSound->bananaPitch += (0.05 * var_a0) / (var_a0 * 64); - } else if (gRacerSound->bananaPitch > 0.05 * var_a0) { - gRacerSound->bananaPitch = 0.05 * var_a0; + if (gRacerSound->bananaPitch < 0.05 * bananas) { + gRacerSound->bananaPitch += (0.05 * bananas) / (bananas * 64); + } else if (gRacerSound->bananaPitch > 0.05 * bananas) { + gRacerSound->bananaPitch = 0.05 * bananas; } - var_f14 += gRacerSound->bananaPitch; + targetPitch += gRacerSound->bananaPitch; } else { gRacerSound->bananaPitch *= 0.95; - var_f14 += gRacerSound->bananaPitch; + targetPitch += gRacerSound->bananaPitch; } - gRacerSound->unk5C[0] += ((var_f14 - gRacerSound->unk5C[0]) / 8); - if (gRacerSound->unk5C[0] > (0x7FFF / 5000.0)) { - gRacerSound->unk5C[0] = (0x7FFF / 5000.0); // 6.5534 + gRacerSound->basePitch[0] += (targetPitch - gRacerSound->basePitch[0]) / 8; + + if (gRacerSound->basePitch[0] > 0x7FFF / 5000.0) { + gRacerSound->basePitch[0] = 0x7FFF / 5000.0; // 6.5534 } - gRacerSound->unk5C[1] = 1.0f; - gRacerSound->unk54[1] = 0; + gRacerSound->basePitch[1] = 1.0f; + gRacerSound->baseVolume[1] = 0; + + // Trigger or stop spinout sound based on spinout timer. if (gSoundRacerObj->playerIndex != PLAYER_COMPUTER && gSoundRacerObj->spinout_timer != 0 && - !gRacerSound->brakeSound) { - gRacerSound->brakeSound = TRUE; - sound_play(SOUND_UNK_13D, &gRacerSound->brakeSoundMask); + !gRacerSound->spinoutSoundOn) { + gRacerSound->spinoutSoundOn = TRUE; + sound_play(SOUND_UNK_13D, &gRacerSound->spinoutSound); } else if (gSoundRacerObj->spinout_timer == 0) { - gRacerSound->brakeSound = FALSE; - if (gRacerSound->brakeSoundMask != NULL) { - sndp_stop(gRacerSound->brakeSoundMask); + gRacerSound->spinoutSoundOn = FALSE; + if (gRacerSound->spinoutSound != NULL) { + sndp_stop(gRacerSound->spinoutSound); } } } @@ -520,25 +618,25 @@ void func_800063EC(Object *obj, UNUSED u32 buttonsPressed, u32 buttonsHeld, s32 void racer_sound_free(Object *obj) { s32 i; - gRacerSound = (VehicleSoundData *) obj->unk64->racer.vehicleSound; + gRacerSound = obj->unk64->racer.vehicleSound; if (gRacerSound != NULL) { for (i = 0; i != 2; i++) { - if (gRacerSound->unk48[i] != NULL) { - sndp_stop(gRacerSound->unk48[i]); - gRacerSound->unk48[i] = 0; + if (gRacerSound->soundHandle[i] != NULL) { + sndp_stop(gRacerSound->soundHandle[i]); + gRacerSound->soundHandle[i] = 0; } } - if (gRacerSound->unk50 != NULL) { - sndp_stop(gRacerSound->unk50); - gRacerSound->unk50 = NULL; + if (gRacerSound->engineIdleSoundHandle != NULL) { + sndp_stop(gRacerSound->engineIdleSoundHandle); + gRacerSound->engineIdleSoundHandle = NULL; } - if (gRacerSound->unkA8 != NULL) { - sndp_stop(gRacerSound->unkA8); - gRacerSound->unkA8 = 0; + if (gRacerSound->brakeSound != NULL) { + sndp_stop(gRacerSound->brakeSound); + gRacerSound->brakeSound = 0; } - for (i = 0; i < ARRAY_COUNT(D_80119C30); i++) { - if (D_80119C30[i] == gRacerSound) { - D_80119C30[i] = NULL; + for (i = 0; i < ARRAY_COUNT(gBackgroundRacerSounds); i++) { + if (gBackgroundRacerSounds[i] == gRacerSound) { + gBackgroundRacerSounds[i] = NULL; } } mempool_free(gRacerSound); @@ -546,252 +644,342 @@ void racer_sound_free(Object *obj) { } } -void func_80006BFC(Object *obj, Camera *camera, Object *obj2, s32 updateRate) { - Object_Racer *racer; - f32 velocity; - f32 xPos; - f32 yPos; - f32 zPos; - f32 new_xPos; - f32 new_zPos; - f32 new_yPos; - f32 var_f2_2; - f32 posSquared; - f32 sp1C; - Object_Racer *racer2; - s32 new_var; +/** + * Calculates the Doppler pitch shift for a given sound source and observer. + * However, it does so in a very strange and error-prone way. + */ +void racer_sound_doppler_effect(Object *observerObj, Camera *camera, Object *sourceObj, s32 tickDelta) { + Object_Racer *observerRacer; + f32 obsSpeed; + f32 xObs; + f32 yObs; + f32 zObs; + f32 deltaX; + f32 deltaZ; + f32 deltaY; + f32 relativeVelocity; + f32 distance; + f32 obsVelRatio; + Object_Racer *sourceRacer; + s32 cents; - racer = &obj->unk64->racer; - racer2 = &obj2->unk64->racer; - gRacerSound = (VehicleSoundData *) racer2->vehicleSound; + /* + The implementation of this function is, to put it mildly, overcomplicated, + does many things incorrectly, and gives the impression that the developer didn't fully + understand the Doppler effect. + + To compute the Doppler effect, you need only the source speed (U) and the observer speed (V) + projected along the line connecting them: + pitchRatio = (C + U) / (C + V), where C is the speed of sound. + + If both speeds are small compared to C, a simple approximation suffices: + pitchRatio = 1 + Vd / C, where Vd is the rate of change of distance between them. + That’s all that’s really needed. + + However, the actual implementation here is unnecessarily convoluted. While the result + is technically not a bug — just a slightly incorrect engine pitch — the strange and + questionable logic deserves to be pointed out. + */ + + observerRacer = &observerObj->unk64->racer; + sourceRacer = &sourceObj->unk64->racer; + gRacerSound = sourceRacer->vehicleSound; if (gRacerSound != NULL) { if (camera != NULL) { - xPos = camera[racer->playerIndex].trans.x_position; - yPos = camera[racer->playerIndex].trans.y_position; - zPos = camera[racer->playerIndex].trans.z_position; - sp1C = 1.0f; + // If the observer is a post-race or cutscene camera, use its position. + // The observer velocity factor is set to 1, since the camera is stationary. + xObs = camera[observerRacer->playerIndex].trans.x_position; + yObs = camera[observerRacer->playerIndex].trans.y_position; + zObs = camera[observerRacer->playerIndex].trans.z_position; + obsVelRatio = 1.0f; } else { - xPos = obj->segment.trans.x_position; - yPos = obj->segment.trans.y_position; - zPos = obj->segment.trans.z_position; - switch (racer->vehicleID) { + // If the observer is a player, things get unnecessarily complex. + // First, fetch the observer's position. + xObs = observerObj->segment.trans.x_position; + yObs = observerObj->segment.trans.y_position; + zObs = observerObj->segment.trans.z_position; + + // Then compute the observer's speed. + switch (observerRacer->vehicleID) { case VEHICLE_CAR: - if (racer->velocity >= 0.0f) { - velocity = racer->velocity; + // Absolute value of forward velocity + if (observerRacer->velocity >= 0.0f) { + obsSpeed = observerRacer->velocity; } else { - velocity = -racer->velocity; + obsSpeed = -observerRacer->velocity; } break; case VEHICLE_HOVERCRAFT: - velocity = sqrtf((obj->segment.x_velocity * obj->segment.x_velocity) + - (obj->segment.z_velocity * obj->segment.z_velocity)); + // 2D ground speed + obsSpeed = sqrtf(observerObj->segment.x_velocity * observerObj->segment.x_velocity + + observerObj->segment.z_velocity * observerObj->segment.z_velocity); break; default: - velocity = sqrtf((obj->segment.x_velocity * obj->segment.x_velocity) + - (obj->segment.z_velocity * obj->segment.z_velocity) + - (obj->segment.y_velocity * obj->segment.y_velocity)); + // Full 3D velocity + obsSpeed = sqrtf(observerObj->segment.x_velocity * observerObj->segment.x_velocity + + observerObj->segment.z_velocity * observerObj->segment.z_velocity + + observerObj->segment.y_velocity * observerObj->segment.y_velocity); break; } - if (velocity > 15.0f) { - velocity = 15.0f; + // For some reason, speed is capped at 15, and a velocity factor is derived from that. + // It's unclear why this is needed at all. + if (obsSpeed > 15.0f) { + obsSpeed = 15.0f; } - sp1C = 1.0f - (velocity / 15.0f); + obsVelRatio = 1.0f - (obsSpeed / 15.0f); } - new_xPos = obj2->segment.trans.x_position - xPos; - new_yPos = obj2->segment.trans.y_position - yPos; - new_zPos = obj2->segment.trans.z_position - zPos; - posSquared = sqrtf(((new_xPos * new_xPos) + (new_yPos * new_yPos)) + (new_zPos * new_zPos)); - var_f2_2 = (gRacerSound->unk6C[racer->playerIndex] - posSquared) / updateRate; - if (var_f2_2 > 15.0f) { - var_f2_2 = 15.0f; - } else if (var_f2_2 < -15.0f) { - var_f2_2 = -15.0f; + + // Calculate the distance between source and observer + deltaX = sourceObj->segment.trans.x_position - xObs; + deltaY = sourceObj->segment.trans.y_position - yObs; + deltaZ = sourceObj->segment.trans.z_position - zObs; + distance = sqrtf(((deltaX * deltaX) + (deltaY * deltaY)) + (deltaZ * deltaZ)); + + // Compute relative velocity — this is actually all that's needed for the Doppler effect! + relativeVelocity = (gRacerSound->prevDistance[observerRacer->playerIndex] - distance) / tickDelta; + if (relativeVelocity > 15.0f) { + relativeVelocity = 15.0f; + } else if (relativeVelocity < -15.0f) { + relativeVelocity = -15.0f; } - new_var = func_80007FA4(gRacerSound->unk5C[0]) * 1731.23404; - gRacerSound->unk68 += - (((alCents2Ratio((((70.0f + var_f2_2) / (70.0f - var_f2_2)) * new_var)) - gRacerSound->unk5C[0]) - - gRacerSound->unk68) / - 2); - gRacerSound->unk68 *= sp1C; - if (gRacerSound->unk68 > 0.8) { - gRacerSound->unk68 = 0.8; - } else if (gRacerSound->unk68 < -0.8) { - gRacerSound->unk68 = -0.8; + + // Now things get weird... + // First, convert the base pitch to cents (logarithmic scale). + cents = log(gRacerSound->basePitch[0]) * 1731.23404; // 1200 / ln(2) + + // Then scale the cents using (70 + v) / (70 - v), which is incorrect. + // Cents are logarithmic and shouldn't be scaled like this. + // Moreover, there's no need to convert to cents and back. + // 70 seems to be acting as the speed of sound here. + gRacerSound->dopplerPitch += (alCents2Ratio((70.0f + relativeVelocity) / (70.0f - relativeVelocity) * cents) - + gRacerSound->basePitch[0] - gRacerSound->dopplerPitch) / + 2; + + // Then the result is again scaled by obsVelRatio, even though observer speed is already part of + // relativeVelocity. This seems redundant and unclear. + gRacerSound->dopplerPitch *= obsVelRatio; + + // Clamp the Doppler pitch shift to ±0.8 + if (gRacerSound->dopplerPitch > 0.8) { + gRacerSound->dopplerPitch = 0.8; + } else if (gRacerSound->dopplerPitch < -0.8) { + gRacerSound->dopplerPitch = -0.8; } - gRacerSound->unk6C[racer->playerIndex] = posSquared; + gRacerSound->prevDistance[observerRacer->playerIndex] = distance; } } -void func_80006FC8(Object **objs, s32 numRacers, Camera *camera, u8 arg3, s32 updateRate) { - f32 tempxPos; - f32 tempyPos; - f32 tempzPos; +/** + * Updates sound parameters for player-controlled vehicles, + * as well as AI-controlled vehicles that drive in the background. + */ +void racer_sound_update_all(Object **racerObjs, s32 numRacers, Camera *cameras, u8 numCameras, s32 tickDelta) { + f32 deltaX; + f32 deltaY; + f32 deltaZ; Object_Racer *racer; - f32 temp_f20_2; - s32 loopCount2; - s32 loopCount1; + f32 idle_intensity; + s32 j; + s32 i; s32 unused; - f32 var_f26; - u8 temp_s3; - u8 v0; - s32 curVal; - s32 loopCount3; - s32 maxVal; + f32 volumeMult; + u8 volume; + u8 backgroundVolume; + s32 curDiff; + s32 k; + s32 maxDiff; s32 curIndex; - f32 sp8C; - VehicleSoundData *temp; - s32 m; + f32 pitch; + VehicleSoundData *soundData; + s32 bestSlot; - for (loopCount1 = 0; loopCount1 < arg3; loopCount1++) { - racer = &objs[loopCount1]->unk64->racer; + // First, calculate engine and idle sound parameters for each player. + for (i = 0; i < numCameras; i++) { + racer = &racerObjs[i]->unk64->racer; if (racer != NULL) { - gRacerSound = (VehicleSoundData *) racer->vehicleSound; + gRacerSound = racer->vehicleSound; } else { gRacerSound = NULL; } - if (gRacerSound != NULL && gRacerSound->unk0[0] != 0) { + if (gRacerSound != NULL && gRacerSound->soundId[0] != 0) { if (racer->raceFinished || check_if_showing_cutscene_camera()) { - tempxPos = objs[loopCount1]->segment.trans.x_position - camera[loopCount1].trans.x_position; - tempyPos = objs[loopCount1]->segment.trans.y_position - camera[loopCount1].trans.y_position; - tempzPos = objs[loopCount1]->segment.trans.z_position - camera[loopCount1].trans.z_position; - func_80006BFC(objs[loopCount1], camera, objs[loopCount1], updateRate); - gRacerSound->unk84 = sqrtf((tempxPos * tempxPos) + (tempyPos * tempyPos) + (tempzPos * tempzPos)); - if (gRacerSound->unk84 < 1500.0f) { - var_f26 = 2250000.0f; //(1500.0f * 1500.0f) - var_f26 = (var_f26 - (gRacerSound->unk84 * gRacerSound->unk84)) / var_f26; - var_f26 *= var_f26; - gRacerSound->unk91[0] = - audspat_calculate_spatial_pan(tempxPos, tempzPos, camera[loopCount1].trans.rotation.y_rotation); + // If the race is finished or a cutscene is playing, the vehicle is considered to move relative to the + // camera, so we calculate the engine sound's pitch, volume, and stereo pan accordingly. + deltaX = racerObjs[i]->segment.trans.x_position - cameras[i].trans.x_position; + deltaY = racerObjs[i]->segment.trans.y_position - cameras[i].trans.y_position; + deltaZ = racerObjs[i]->segment.trans.z_position - cameras[i].trans.z_position; + racer_sound_doppler_effect(racerObjs[i], cameras, racerObjs[i], tickDelta); + gRacerSound->distToCamera = sqrtf((deltaX * deltaX) + (deltaY * deltaY) + (deltaZ * deltaZ)); + + // Engine sounds are inaudible beyond 1500 units. + if (gRacerSound->distToCamera < 1500.0f) { + volumeMult = 2250000.0f; // 1500.0f * 1500.0f; + volumeMult = (volumeMult - (gRacerSound->distToCamera * gRacerSound->distToCamera)) / volumeMult; + volumeMult *= volumeMult; + gRacerSound->pan = + audspat_calculate_spatial_pan(deltaX, deltaZ, cameras[i].trans.rotation.y_rotation); } else { - var_f26 = 0.0f; + volumeMult = 0.0f; } - if (racer->raceFinished == 0) { - var_f26 *= 0.5; + if (!racer->raceFinished) { + // In cutscenes, engine volume is reduced by half. + volumeMult *= 0.5; } } else { - var_f26 = 1.0f; - gRacerSound->unk91[0] = 64; - gRacerSound->unk68 = 0.0f; - } - if ((gRacerSound->unkA0 < 70) && (gRacerSound->unk36) && (arg3 < 3) && (var_f26 != 0.0) && - !(gRacerSound->unk44[0] & 1)) { - temp_f20_2 = gRacerSound->unkA0 / 70.0f; - temp_s3 = (gRacerSound->unk37 - (gRacerSound->unk37 * temp_f20_2)) * var_f26; - if (temp_s3 >= 16) { - if (gRacerSound->unk50 == NULL) { - func_80001F14(gRacerSound->unk36, &gRacerSound->unk50); - } - sp8C = gRacerSound->unk38 / 100.0f + - ((((f32) gRacerSound->unk39 / 100.0f) - gRacerSound->unk38 / 100.0f) * temp_f20_2); - if (gRacerSound->unk50 != NULL) { - audspat_calculate_echo(gRacerSound->unk50, objs[loopCount1]->segment.trans.x_position, - objs[loopCount1]->segment.trans.y_position, - objs[loopCount1]->segment.trans.z_position); - sndp_set_param(gRacerSound->unk50, AL_SNDP_VOL_EVT, temp_s3 << 8); - sndp_set_param(gRacerSound->unk50, AL_SNDP_PITCH_EVT, *((u32 *) &sp8C)); - sndp_set_priority(gRacerSound->unk50, 80); - sndp_set_param(gRacerSound->unk50, AL_SNDP_PAN_EVT, gRacerSound->unk91[0]); - } - } else if (gRacerSound->unk50 != NULL) { - sndp_stop(gRacerSound->unk50); - gRacerSound->unk50 = 0; - } - } else if (gRacerSound->unk50 != NULL) { - sndp_stop(gRacerSound->unk50); - gRacerSound->unk50 = 0; + volumeMult = 1.0f; + gRacerSound->pan = 64; + gRacerSound->dopplerPitch = 0.0f; } - for (loopCount2 = 0; loopCount2 < 2 && gRacerSound->unk0[loopCount2] != 0 && var_f26 != 0.0; loopCount2++) { - temp_s3 = gRacerSound->unk54[loopCount2] * var_f26; - sp8C = gRacerSound->unk5C[loopCount2] + gRacerSound->bananaPitch + gRacerSound->enginePitch + - gRacerSound->unk68; - if (sp8C < 0.05) { - sp8C = 0.05f; + // If the engine intensity is below 70, play an idle engine sound. + // The lower the intensity, the louder the idle sound. + // This is only applied when there are 1 or 2 players to avoid excessive sound generation. + if (gRacerSound->engine_intensity < 70 && gRacerSound->engineIdleSound != 0 && numCameras <= 2 && + volumeMult != 0.0 && !(gRacerSound->soundDisabled[0] & 1)) { + + idle_intensity = gRacerSound->engine_intensity / 70.0f; + volume = + (gRacerSound->engineIdleMaxVolume - gRacerSound->engineIdleMaxVolume * idle_intensity) * volumeMult; + + // If volume is above threshold, update idle sound parameters. + if (volume >= 16) { + if (gRacerSound->engineIdleSoundHandle == NULL) { + func_80001F14(gRacerSound->engineIdleSound, &gRacerSound->engineIdleSoundHandle); + } + pitch = gRacerSound->engineIdleMaxPitch / 100.0f + ((f32) gRacerSound->engineIdleMinPitch / 100.0f - + gRacerSound->engineIdleMaxPitch / 100.0f) * + idle_intensity; + if (gRacerSound->engineIdleSoundHandle != NULL) { + audspat_calculate_echo( + gRacerSound->engineIdleSoundHandle, racerObjs[i]->segment.trans.x_position, + racerObjs[i]->segment.trans.y_position, racerObjs[i]->segment.trans.z_position); + sndp_set_param(gRacerSound->engineIdleSoundHandle, AL_SNDP_VOL_EVT, volume << 8); + sndp_set_param(gRacerSound->engineIdleSoundHandle, AL_SNDP_PITCH_EVT, *((u32 *) &pitch)); + sndp_set_priority(gRacerSound->engineIdleSoundHandle, 80); + sndp_set_param(gRacerSound->engineIdleSoundHandle, AL_SNDP_PAN_EVT, gRacerSound->pan); + } + } else if (gRacerSound->engineIdleSoundHandle != NULL) { + // Otherwise, stop the idle sound if it was playing. + sndp_stop(gRacerSound->engineIdleSoundHandle); + gRacerSound->engineIdleSoundHandle = NULL; } - if ((loopCount2 == 0) && (gRacerSound->unk44[0] & 1)) { - if (gRacerSound->unk48[0] != NULL) { - sndp_stop(gRacerSound->unk48[0]); - gRacerSound->unk48[0] = NULL; + } else if (gRacerSound->engineIdleSoundHandle != NULL) { + sndp_stop(gRacerSound->engineIdleSoundHandle); + gRacerSound->engineIdleSoundHandle = NULL; + } + + // Start or stop engine sounds based on current conditions. + for (j = 0; j < 2 && gRacerSound->soundId[j] != 0 && volumeMult != 0.0; j++) { + volume = gRacerSound->baseVolume[j] * volumeMult; + + //!@bug bananaPitch is added twice. + pitch = gRacerSound->basePitch[j] + gRacerSound->bananaPitch + gRacerSound->enginePitch + + gRacerSound->dopplerPitch; + if (pitch < 0.05) { + pitch = 0.05f; + } + + // If engine sound is disabled, stop it. + if (j == 0 && (gRacerSound->soundDisabled[0] & 1)) { + if (gRacerSound->soundHandle[0] != NULL) { + sndp_stop(gRacerSound->soundHandle[0]); + gRacerSound->soundHandle[0] = NULL; } } else { - if ((gRacerSound->unk48[loopCount2] != NULL) && (temp_s3 == 0)) { - sndp_stop(gRacerSound->unk48[loopCount2]); - gRacerSound->unk48[loopCount2] = NULL; + // If sound handle exists but volume is zero, stop the sound. + if (gRacerSound->soundHandle[j] != NULL && volume == 0) { + sndp_stop(gRacerSound->soundHandle[j]); + gRacerSound->soundHandle[j] = NULL; } else { - if (gRacerSound->unk48[loopCount2] == NULL) { - func_80001F14(gRacerSound->unk0[loopCount2], &gRacerSound->unk48[loopCount2]); + // Otherwise, start or update the engine sound parameters. + if (gRacerSound->soundHandle[j] == NULL) { + func_80001F14(gRacerSound->soundId[j], &gRacerSound->soundHandle[j]); } - if (gRacerSound->unk48[loopCount2] != NULL) { - audspat_calculate_echo( - gRacerSound->unk48[loopCount2], objs[loopCount1]->segment.trans.x_position, - objs[loopCount1]->segment.trans.y_position, objs[loopCount1]->segment.trans.z_position); - sndp_set_param(gRacerSound->unk48[loopCount2], AL_SNDP_VOL_EVT, temp_s3 << 8); - sndp_set_param(gRacerSound->unk48[loopCount2], AL_SNDP_PITCH_EVT, *((u32 *) &sp8C)); - sndp_set_priority(gRacerSound->unk48[loopCount2], 80); - if (arg3 != 1) { - gRacerSound->unk91[0] = 64; + if (gRacerSound->soundHandle[j] != NULL) { + audspat_calculate_echo(gRacerSound->soundHandle[j], racerObjs[i]->segment.trans.x_position, + racerObjs[i]->segment.trans.y_position, + racerObjs[i]->segment.trans.z_position); + sndp_set_param(gRacerSound->soundHandle[j], AL_SNDP_VOL_EVT, volume << 8); + sndp_set_param(gRacerSound->soundHandle[j], AL_SNDP_PITCH_EVT, *((u32 *) &pitch)); + sndp_set_priority(gRacerSound->soundHandle[j], 80); + if (numCameras != 1) { + gRacerSound->pan = 64; } - sndp_set_param(gRacerSound->unk48[loopCount2], AL_SNDP_PAN_EVT, gRacerSound->unk91[0]); + sndp_set_param(gRacerSound->soundHandle[j], AL_SNDP_PAN_EVT, gRacerSound->pan); } } } } } } - if (arg3 >= 3) { + + // Next: manage engine sounds for AI-controlled vehicles. + // These background engine sounds are only active in 1-2 player mode, + // and only the two loudest sounds are allowed to play simultaneously. + + // Skip background sounds entirely if more than 2 players. + if (numCameras > 2) { return; } - for (loopCount2 = arg3; loopCount2 < numRacers; loopCount2++) { - racer = &objs[loopCount2]->unk64->racer; + // First, reset background volume for each AI vehicle. + for (j = numCameras; j < numRacers; j++) { + racer = &racerObjs[j]->unk64->racer; if (racer != NULL) { gRacerSound = racer->vehicleSound; if (gRacerSound != NULL) { - temp = gRacerSound; - temp->unk88 = 0; + soundData = gRacerSound; + soundData->backgroundVolume = 0; } } } - for (loopCount1 = 0; loopCount1 < arg3; loopCount1++) { - racer = &objs[loopCount1]->unk64->racer; - for (loopCount2 = arg3; loopCount2 < numRacers; loopCount2++) { - if (objs[loopCount2]->unk64 != NULL) { - gRacerSound = objs[loopCount2]->unk64->racer.vehicleSound; - if (gRacerSound != 0) { - if (racer->raceFinished != 0) { - tempxPos = objs[loopCount2]->segment.trans.x_position - camera[loopCount1].trans.x_position; - tempyPos = objs[loopCount2]->segment.trans.y_position - camera[loopCount1].trans.y_position; - tempzPos = objs[loopCount2]->segment.trans.z_position - camera[loopCount1].trans.z_position; + + // Then, calculate the background volume for each AI vehicle, + // determining which camera hears it the loudest (volume decreases with distance). + // Doppler effect is the only pitch modifier applied here. + + for (i = 0; i < numCameras; i++) { + racer = &racerObjs[i]->unk64->racer; + for (j = numCameras; j < numRacers; j++) { + if (racerObjs[j]->unk64 != NULL) { + gRacerSound = racerObjs[j]->unk64->racer.vehicleSound; + if (gRacerSound != NULL) { + if (racer->raceFinished) { + deltaX = racerObjs[j]->segment.trans.x_position - cameras[i].trans.x_position; + deltaY = racerObjs[j]->segment.trans.y_position - cameras[i].trans.y_position; + deltaZ = racerObjs[j]->segment.trans.z_position - cameras[i].trans.z_position; } else { - tempxPos = - objs[loopCount2]->segment.trans.x_position - objs[loopCount1]->segment.trans.x_position; - tempyPos = - objs[loopCount2]->segment.trans.y_position - objs[loopCount1]->segment.trans.y_position; - tempzPos = - objs[loopCount2]->segment.trans.z_position - objs[loopCount1]->segment.trans.z_position; + deltaX = racerObjs[j]->segment.trans.x_position - racerObjs[i]->segment.trans.x_position; + deltaY = racerObjs[j]->segment.trans.y_position - racerObjs[i]->segment.trans.y_position; + deltaZ = racerObjs[j]->segment.trans.z_position - racerObjs[i]->segment.trans.z_position; } - gRacerSound->unk84 = sqrtf((tempxPos * tempxPos) + (tempyPos * tempyPos) + (tempzPos * tempzPos)); - if (gRacerSound->unk84 < 1500.0f) { - var_f26 = 2250000.0f; //(1500.0f * 1500.0f) - var_f26 = (var_f26 - (gRacerSound->unk84 * gRacerSound->unk84)) / var_f26; - v0 = gRacerSound->unk54[0] * var_f26; - if (v0 > 127) { - v0 = 127; + gRacerSound->distToCamera = sqrtf((deltaX * deltaX) + (deltaY * deltaY) + (deltaZ * deltaZ)); + if (gRacerSound->distToCamera < 1500.0f) { + volumeMult = 2250000.0f; //(1500.0f * 1500.0f) + volumeMult = (volumeMult - gRacerSound->distToCamera * gRacerSound->distToCamera) / volumeMult; + + backgroundVolume = gRacerSound->baseVolume[0] * volumeMult; + if (backgroundVolume > 127) { + backgroundVolume = 127; } - v0 *= 0.8; - if (gRacerSound->unk88 < v0) { - gRacerSound->unk88 = v0; - gRacerSound->unk91[0] = - audspat_calculate_spatial_pan(tempxPos, tempzPos, camera->trans.rotation.y_rotation); - if (racer->raceFinished != 0) { - func_80006BFC(objs[loopCount1], camera, objs[loopCount2], updateRate); + + // All background sounds are played at 80% of the computed volume. + backgroundVolume *= 0.8; + + // Store sound parameters for the camera that hears it the loudest. + if (gRacerSound->backgroundVolume < backgroundVolume) { + gRacerSound->backgroundVolume = backgroundVolume; + gRacerSound->pan = + audspat_calculate_spatial_pan(deltaX, deltaZ, cameras->trans.rotation.y_rotation); + if (racer->raceFinished) { + racer_sound_doppler_effect(racerObjs[i], cameras, racerObjs[j], tickDelta); } else { - func_80006BFC(objs[loopCount1], NULL, objs[loopCount2], updateRate); + racer_sound_doppler_effect(racerObjs[i], NULL, racerObjs[j], tickDelta); } - gRacerSound->unk8C = gRacerSound->unk5C[0] + gRacerSound->unk68; - if (gRacerSound->unk8C < 0.05) { - gRacerSound->unk8C = 0.05f; + gRacerSound->backgroundPitch = gRacerSound->basePitch[0] + gRacerSound->dopplerPitch; + if (gRacerSound->backgroundPitch < 0.05) { + gRacerSound->backgroundPitch = 0.05f; } } } @@ -800,59 +988,75 @@ void func_80006FC8(Object **objs, s32 numRacers, Camera *camera, u8 arg3, s32 up } } - for (loopCount3 = 0; loopCount3 < ARRAY_COUNT(D_80119C30); loopCount3++) { - if (D_80119C30[loopCount3] != NULL) { - if (D_80119C30[loopCount3]->unk48[0] != NULL && D_80119C30[loopCount3]->unk88 < 8) { - sndp_stop(D_80119C30[loopCount3]->unk48[0]); - D_80119C30[loopCount3]->unk48[0] = NULL; - D_80119C30[loopCount3]->unk74 = 0; - D_80119C30[loopCount3] = NULL; + // Select up to 2 background engine sounds to play. + + // First, stop any playing background sounds if they are too quiet. + for (k = 0; k < ARRAY_COUNT(gBackgroundRacerSounds); k++) { + if (gBackgroundRacerSounds[k] != NULL) { + if (gBackgroundRacerSounds[k]->soundHandle[0] != NULL && gBackgroundRacerSounds[k]->backgroundVolume < 8) { + sndp_stop(gBackgroundRacerSounds[k]->soundHandle[0]); + gBackgroundRacerSounds[k]->soundHandle[0] = NULL; + gBackgroundRacerSounds[k]->backgroundState = VEHICLE_BACKGROUND_STOPPED; + gBackgroundRacerSounds[k] = NULL; } } } - if (updateRate < D_800DC6D4) { - D_800DC6D4 -= updateRate; + + // Advance the background sound swap timer. + if (tickDelta < gBackgroundSoundSwapTimer) { + gBackgroundSoundSwapTimer -= tickDelta; } else { - D_800DC6D4 = 0; + gBackgroundSoundSwapTimer = 0; } - for (loopCount2 = 1; loopCount2 < numRacers; loopCount2++) { - racer = &objs[loopCount2]->unk64->racer; - if (objs[loopCount2]->unk64 != NULL) { + // Replace background sounds based on volume priority. + //!@bug: loop starts from 1 instead of numCameras — possibly unintended. + for (j = 1; j < numRacers; j++) { + racer = &racerObjs[j]->unk64->racer; + if (racerObjs[j]->unk64 != NULL) { gRacerSound = racer->vehicleSound; if (gRacerSound != NULL) { - if (gRacerSound->unk74 == 0) { - maxVal = 20; - if (gRacerSound->unk0[0] != 0) { - m = -1; - for (loopCount3 = 0; loopCount3 < ARRAY_COUNT(D_80119C30); loopCount3++) { + // If a sound is currently stopped, check whether it should be restarted and find a suitable slot. + if (gRacerSound->backgroundState == VEHICLE_BACKGROUND_STOPPED) { + // Replacement only happens if the new sound is at least 20 units louder than the current one. + // This likely prevents rapid switching between background sounds. + maxDiff = 20; + if (gRacerSound->soundId[0] != 0) { + bestSlot = -1; + // Search for a suitable slot (up to 2). Prefer empty slots, or replace the quietest if timer + // allows. + for (k = 0; k < ARRAY_COUNT(gBackgroundRacerSounds); k++) { if (1) { // FAKE MATCH - temp = D_80119C30[loopCount3]; - if (temp != NULL) { - curVal = gRacerSound->unk88; - curVal -= temp->unk88; - if ((maxVal < curVal) && (D_800DC6D4 == 0)) { - m = loopCount3; - maxVal = curVal; + soundData = gBackgroundRacerSounds[k]; + if (soundData != NULL) { + curDiff = gRacerSound->backgroundVolume; + curDiff -= soundData->backgroundVolume; + if (maxDiff < curDiff && gBackgroundSoundSwapTimer == 0) { + bestSlot = k; + maxDiff = curDiff; } - } else if (gRacerSound->unk88 >= 9) { - m = loopCount3; + } else if (gRacerSound->backgroundVolume > 8) { + bestSlot = k; } } } - if (m != -1) { - gRacerSound->unk74 = 2; - if (D_80119C30[m] != NULL) { - if (D_80119C30[m]->unk48[0] != NULL) { - sndp_stop(D_80119C30[m]->unk48[0]); - D_80119C30[m]->unk48[0] = NULL; - gRacerSound->unk74 = 1; + if (bestSlot != -1) { + // If a replacement is found, stop the old sound before starting the new one. + // backgroundState is temporarily set to PENDING to defer actual sound playback for one + // frame. + gRacerSound->backgroundState = VEHICLE_BACKGROUND_PLAYING; + if (gBackgroundRacerSounds[bestSlot] != NULL) { + if (gBackgroundRacerSounds[bestSlot]->soundHandle[0] != NULL) { + sndp_stop(gBackgroundRacerSounds[bestSlot]->soundHandle[0]); + gBackgroundRacerSounds[bestSlot]->soundHandle[0] = NULL; + gRacerSound->backgroundState = VEHICLE_BACKGROUND_PENDING; } - D_800DC6D4 = 60; - D_80119C30[m]->unk74 = 0; + // Prevent further changes to the background slots for the next 60 frames. + gBackgroundSoundSwapTimer = 60; + gBackgroundRacerSounds[bestSlot]->backgroundState = VEHICLE_BACKGROUND_STOPPED; } - D_80119C30[m] = gRacerSound; + gBackgroundRacerSounds[bestSlot] = gRacerSound; } } } @@ -860,27 +1064,32 @@ void func_80006FC8(Object **objs, s32 numRacers, Camera *camera, u8 arg3, s32 up } } + // Finally, set parameters for all active background sounds (AI vehicles). if (get_race_countdown() <= 0) { - for (loopCount3 = 0; loopCount3 < ARRAY_COUNT(D_80119C30); loopCount3++) { - temp = D_80119C30[loopCount3]; - if (temp != NULL) { - if (temp->unk0[0] != 0) { - if (temp->unk74 == 1) { - temp->unk74 = 2; + for (k = 0; k < ARRAY_COUNT(gBackgroundRacerSounds); k++) { + soundData = gBackgroundRacerSounds[k]; + if (soundData != NULL) { + if (soundData->soundId[0] != 0) { + // If the sound is pending, transition it to playing. + // Otherwise, start or update its parameters. + if (soundData->backgroundState == VEHICLE_BACKGROUND_PENDING) { + soundData->backgroundState = VEHICLE_BACKGROUND_PLAYING; } else { - if (temp->unk48[0] == NULL) { - func_80001F14(temp->unk0[0], &temp->unk48[0]); + if (soundData->soundHandle[0] == NULL) { + func_80001F14(soundData->soundId[0], &soundData->soundHandle[0]); } - if (temp->unk48[0] != NULL) { - audspat_calculate_echo(temp->unk48[0], temp->racerPos.x, temp->racerPos.y, - temp->racerPos.z); - sndp_set_param(temp->unk48[0], AL_SNDP_VOL_EVT, temp->unk88 << 8); - sndp_set_param(temp->unk48[0], AL_SNDP_PITCH_EVT, *((u32 *) &temp->unk8C)); - if (arg3 != 1) { - temp->unk91[0] = 64; + if (soundData->soundHandle[0] != NULL) { + audspat_calculate_echo(soundData->soundHandle[0], soundData->racerPos.x, + soundData->racerPos.y, soundData->racerPos.z); + sndp_set_param(soundData->soundHandle[0], AL_SNDP_VOL_EVT, + soundData->backgroundVolume << 8); + sndp_set_param(soundData->soundHandle[0], AL_SNDP_PITCH_EVT, + *((u32 *) &soundData->backgroundPitch)); + if (numCameras != 1) { + soundData->pan = 64; } - sndp_set_param(temp->unk48[0], AL_SNDP_PAN_EVT, temp->unk91[0]); - sndp_set_priority(temp->unk48[0], 70); + sndp_set_param(soundData->soundHandle[0], AL_SNDP_PAN_EVT, soundData->pan); + sndp_set_priority(soundData->soundHandle[0], 70); } } } @@ -892,41 +1101,45 @@ void func_80006FC8(Object **objs, s32 numRacers, Camera *camera, u8 arg3, s32 up /** * Enable the vehicle sounds made during gameplay. */ -UNUSED void sound_vehicle_enable(void) { +UNUSED void racer_sound_enable(void) { gVehicleSounds = TRUE; } /** * Disable the vehicle sounds made during gameplay. */ -UNUSED void sound_vehicle_disable(void) { +UNUSED void racer_sound_disable(void) { gVehicleSounds = FALSE; } /** * Return whether vehicle sounds should be playing during gameplay. */ -UNUSED u8 sound_vehicle_check(void) { +UNUSED u8 racer_sound_check(void) { return gVehicleSounds; } -// This is likely an arctanh function. -f32 func_80007FA4(f32 arg0) { - f32 temp_f0; - f32 temp_f12; - f32 var_f14; - f32 var_f2; - s32 var_v0; +/** + * Returns the natural logarithm of the given argument. + * Uses a Maclaurin series expansion for the inverse hyperbolic tangent (artanh) for the calculation. + */ +f32 log(f32 x) { + f32 prev_sum; + f32 x_squared; + f32 power; + f32 sum; + s32 n; - var_f2 = 0.0f; - temp_f0 = -1.0f; - arg0 = (arg0 - 1.0f) / (1.0f + arg0); - var_f14 = arg0; - temp_f12 = arg0 * arg0; - for (var_v0 = 1; (var_f2 - temp_f0) > 0.001; var_v0 += 2) { - temp_f0 = var_f2; - var_f2 += var_f14 / var_v0; - var_f14 *= temp_f12; + sum = 0.0f; + prev_sum = -1.0f; + x = (x - 1.0f) / (1.0f + x); + power = x; + x_squared = x * x; + // sum = sum(x^n/n) + for (n = 1; (sum - prev_sum) > 0.001; n += 2) { + prev_sum = sum; + sum += power / n; // power = x^n + power *= x_squared; } - return var_f2 * 2; + return sum * 2; } diff --git a/src/audio_vehicle.h b/src/audio_vehicle.h index 81b7fba4..fcb7c7a2 100644 --- a/src/audio_vehicle.h +++ b/src/audio_vehicle.h @@ -4,87 +4,94 @@ #include "types.h" #include "structs.h" #include "audio.h" +#include "camera.h" + +enum VehicleBackgroundSoundStates { + VEHICLE_BACKGROUND_STOPPED, + VEHICLE_BACKGROUND_PENDING, + VEHICLE_BACKGROUND_PLAYING +}; /* Size: 0xE0 / 224 bytes */ typedef struct VehicleSoundData { - /* 0x00 */ u16 unk0[2]; - /* 0x04 */ u8 unk4[2][5]; - /* 0x0E */ u8 unkE[2][5]; - /* 0x18 */ u16 unk18[2][5]; - /* 0x2C */ u8 unk2C[2][5]; - /* 0x36 */ u8 unk36; - /* 0x37 */ u8 unk37; - /* 0x38 */ u8 unk38; - /* 0x39 */ u8 unk39; - /* 0x3A */ u8 pad3A[0x2]; + /* 0x00 */ u16 soundId[2]; + /* 0x04 */ u8 intensityLevelsForPitch[2][5]; + /* 0x0E */ u8 intensityLevelsForVolume[2][5]; + /* 0x18 */ u16 pitchLevels[2][5]; // 10000 = 1.0 + /* 0x2C */ u8 volumeLevels[2][5]; + /* 0x36 */ u8 engineIdleSound; + /* 0x37 */ u8 engineIdleMaxVolume; + /* 0x38 */ u8 engineIdleMaxPitch; // 100 = 1.0 + /* 0x39 */ u8 engineIdleMinPitch; // 100 = 1.0 /* 0x3C */ f32 bananaPitch; - /* 0x40 */ f32 unk40; - /* 0x44 */ u8 unk44[4]; - /* 0x48 */ SoundHandle unk48[2]; //soundMask / soundState? - /* 0x50 */ SoundHandle unk50; - /* 0x54 */ f32 unk54[2]; - /* 0x5C */ f32 unk5C[2]; - /* 0x64 */ u8 unk64; - /* 0x68 */ f32 unk68; - /* 0x6C */ f32 unk6C[2]; - /* 0x74 */ u8 unk74; + /* 0x40 */ f32 driftPitch; + /* 0x44 */ u8 soundDisabled[4]; + /* 0x48 */ SoundHandle soundHandle[2]; + /* 0x50 */ SoundHandle engineIdleSoundHandle; + /* 0x54 */ f32 baseVolume[2]; + /* 0x5C */ f32 basePitch[2]; + /* 0x64 */ u8 unk64_unused; + /* 0x68 */ f32 dopplerPitch; + /* 0x6C */ f32 prevDistance[2]; + /* 0x74 */ u8 backgroundState; /* 0x78 */ Vec3f racerPos; - /* 0x84 */ f32 unk84; - /* 0x88 */ u8 unk88; // Volume? - /* 0x8C */ f32 unk8C; // Volume? - /* 0x90 */ s8 unk90; - /* 0x91 */ u8 unk91[3]; + /* 0x84 */ f32 distToCamera; + /* 0x88 */ u8 backgroundVolume; + /* 0x8C */ f32 backgroundPitch; + /* 0x90 */ s8 engineJitter; + /* 0x91 */ u8 pan; /* 0x94 */ f32 enginePitch; // Engine noise for the car. - /* 0x98 */ u8 unk98; + /* 0x98 */ u8 unk98_unused; /* 0x99 */ u8 pad99[0x7]; - /* 0xA0 */ u8 unkA0; - /* 0xA4 */ f32 throttlePitch; // Engine noise for the hovercraft and plane. - /* 0xA8 */ SoundHandle unkA8; - /* 0xAC */ u16 unkAC; - /* 0xB0 */ f32 throttlePitchVel; - /* 0xB4 */ f32 throttlePitchDecay; - /* 0xB8 */ u8 unkB8; - /* 0xBC */ f32 unkBC; - /* 0xC0 */ f32 unkC0; - /* 0xC4 */ f32 unkC4; - /* 0xC8 */ f32 throttlePitchCeil; - /* 0xCC */ f32 unkCC; - /* 0xD0 */ u8 unkD0; - /* 0xD4 */ f32 basePitch; - /* 0xD8 */ u8 brakeSound; //Sound is playing bool? - /* 0xDC */ SoundHandle brakeSoundMask; //soundMask / soundState? + /* 0xA0 */ u8 engine_intensity; + /* 0xA4 */ f32 thrustPitch; // Engine noise for the hovercraft and plane. + /* 0xA8 */ SoundHandle brakeSound; + /* 0xAC */ u16 brakeSoundVolume; + /* 0xB0 */ f32 thrustPitchVel; + /* 0xB4 */ f32 thrustPitchDecay; + /* 0xB8 */ u8 unkB8_unused; + /* 0xBC */ f32 pitchLateralSpeedScale; + /* 0xC0 */ f32 rollAnglePitchScale; + /* 0xC4 */ f32 pitchAnglePitchScale; + /* 0xC8 */ f32 thrustPitchMax; + /* 0xCC */ f32 thrustPitchSpeedScale; + /* 0xD0 */ u8 airTime; + /* 0xD4 */ f32 planeHovercraftBasePitch; + /* 0xD8 */ u8 spinoutSoundOn; // bool + /* 0xDC */ SoundHandle spinoutSound; } VehicleSoundData; /* Size: 0x4C / 76 Bytes */ -typedef struct unkAudioAsset { - /* 0x00 */ u16 unk0[2]; - /* 0x04 */ u8 unk4[2][5]; - /* 0x0E */ u8 unkE[2][5]; - /* 0x18 */ u16 unk18[2][5]; - /* 0x2C */ u8 unk2C[2][5]; - /* 0x36 */ u8 unk36; - /* 0x37 */ u8 unk37; - /* 0x38 */ u8 unk38; - /* 0x39 */ u8 unk39; - /* 0x3A */ u8 unk3A; - /* 0x3B */ u8 unk3B; - /* 0x3C */ s16 unk3C; - /* 0x3E */ s16 unk3E; - /* 0x40 */ s16 unk40; - /* 0x32 */ s16 unk42; - /* 0x44 */ s16 unk44; - /* 0x46 */ s16 unk46; - /* 0x48 */ s16 unk48; - /* 0x4A */ u8 unk4A; -} unkAudioAsset; +typedef struct VehicleSoundAsset { + /* 0x00 */ u16 soundId[2]; + /* 0x04 */ u8 intensityLevelsForPitch[2][5]; + /* 0x0E */ u8 intensityLevelsForVolume[2][5]; + /* 0x18 */ u16 pitchLevels[2][5]; // 10000 = 1.0 + /* 0x2C */ u8 volumeLevels[2][5]; + /* 0x36 */ u8 engineIdleSound; + /* 0x37 */ u8 engineIdleMaxVolume; + /* 0x38 */ u8 engineIdleMaxPitch; + /* 0x39 */ u8 engineIdleMinPitch; + /* 0x3A */ u8 unk3A_unused; + /* 0x3B */ u8 unk3B_unused; + /* 0x3C */ s16 pitchLateralSpeedScale; // 10000 = 1.0 + /* 0x3E */ s16 thrustPitchVel; // 10000 = 1.0 + /* 0x40 */ s16 thrustPitchDecay; // 10000 = 1.0 + /* 0x32 */ s16 rollAnglePitchScale; // 10000 = 1.0 + /* 0x44 */ s16 pitchAnglePitchScale; // 10000 = 1.0 + /* 0x46 */ s16 thrustPitchMax; // 10000 = 1.0 + /* 0x48 */ s16 thrustPitchSpeedScale; // 10000 = 1.0 + /* 0x4A */ u8 planeHovercraftBasePitch; +} VehicleSoundAsset; -void racer_sound_update(Object *obj, u32 buttonsPressed, u32 buttonsHeld, s32 updateRate); -void racer_sound_free(Object *); - -f32 func_80007FA4(f32 arg0); +void racer_sound_update(Object *obj, u32 buttonsPressed, u32 buttonsHeld, s32 tickDelta); +void racer_sound_free(Object *obj); +void racer_sound_doppler_effect(Object *observerObj, Camera *camera, Object *sourceObj, s32 tickDelta); +f32 log(f32 x); VehicleSoundData *racer_sound_init(s32 characterId, s32 vehicleId); -void func_80005254(Object *obj, u32 buttonsPressed, u32 buttonsHeld, s32 updateRate); -void racer_sound_hovercraft(Object *, u32 buttonsPressed, u32 buttonsHeld, s32 updateRate); -void func_800063EC(Object *, u32 buttonsPressed, u32 buttonsHeld, s32 updateRate); +void racer_sound_car(Object *obj, u32 buttonsPressed, u32 buttonsHeld, s32 tickDelta); +void racer_sound_hovercraft(Object *, u32 buttonsPressed, u32 buttonsHeld, s32 tickDelta); +void racer_sound_plane(Object *, u32 buttonsPressed, u32 buttonsHeld, s32 tickDelta); +void racer_sound_update_all(Object **racerObjs, s32 numRacers, Camera *cameras, u8 numCameras, s32 tickDelta); #endif diff --git a/src/camera.c b/src/camera.c index 2c966adf..1d2a77d7 100644 --- a/src/camera.c +++ b/src/camera.c @@ -950,7 +950,7 @@ void set_ortho_matrix_view(Gfx **dList, MatrixS **mtx) { void func_8006807C(Gfx **dList, MatrixS **mtx) { object_inverse_transform_to_matrix(gCurrentModelMatrixF, &D_800DD288); f32_matrix_mult(&gCurrentModelMatrixF, &gPerspectiveMatrixF, &gViewMatrixF); - object_inverse_transform_to_matrix((float(*)[4]) gModelMatrixF[0], &D_800DD2A0); + object_inverse_transform_to_matrix((float (*)[4]) gModelMatrixF[0], &D_800DD2A0); f32_matrix_mult(gModelMatrixF[0], &gViewMatrixF, &gCurrentModelMatrixF); f32_matrix_to_s16_matrix(&gCurrentModelMatrixF, *mtx); gSPMatrixDKR((*dList)++, OS_K0_TO_PHYSICAL((*mtx)++), G_MTX_DKR_INDEX_0); diff --git a/src/hasm/math_util.c b/src/hasm/math_util.c index 733b2502..dc195d81 100644 --- a/src/hasm/math_util.c +++ b/src/hasm/math_util.c @@ -163,7 +163,7 @@ GLOBAL_ASM("asm/math_util/f32_matrix_mult.s") #ifdef NON_MATCHING /* Official name: mathMtxF2L */ void f32_matrix_to_s16_matrix(Matrix *input, MatrixS *output) { - guMtxF2L((float(*)[4]) input, (Mtx *) output); + guMtxF2L((float (*)[4]) input, (Mtx *) output); } #else GLOBAL_ASM("asm/math_util/f32_matrix_to_s16_matrix.s") diff --git a/src/objects.c b/src/objects.c index ccc00ef2..b8ce9559 100644 --- a/src/objects.c +++ b/src/objects.c @@ -4235,12 +4235,12 @@ void func_80016748(Object *obj0, Object *obj1) { if (!((objModel->unk3C + 50.0) < sqrtf((xDiff * xDiff) + (yDiff * yDiff) + (zDiff * zDiff)))) { obj0Interact = obj0->interactObj; obj1Interact = obj1->interactObj; - object_transform_to_matrix((float(*)[4]) obj1TransformMtx, &obj1->segment.trans); + object_transform_to_matrix((float (*)[4]) obj1TransformMtx, &obj1->segment.trans); for (i = 0; i < objModel->unk20; i += 2) { xDiff = obj1->curVertData[objModel->unk1C[i]].x; yDiff = obj1->curVertData[objModel->unk1C[i]].y; zDiff = obj1->curVertData[objModel->unk1C[i]].z; - guMtxXFMF((float(*)[4]) obj1TransformMtx, xDiff, yDiff, zDiff, &xDiff, &yDiff, &zDiff); + guMtxXFMF((float (*)[4]) obj1TransformMtx, xDiff, yDiff, zDiff, &xDiff, &yDiff, &zDiff); temp = (((f32) objModel->unk1C[i + 1] / 64) * obj1->segment.trans.scale) * 50.0; xDiff -= obj0->segment.trans.x_position; yDiff -= obj0->segment.trans.y_position; @@ -4407,7 +4407,7 @@ void func_8001709C(Object *obj) { sp78.x_position = -obj->segment.trans.x_position; sp78.y_position = -obj->segment.trans.y_position; sp78.z_position = -obj->segment.trans.z_position; - object_inverse_transform_to_matrix((float(*)[4]) sp6C, &sp78); + object_inverse_transform_to_matrix((float (*)[4]) sp6C, &sp78); inverseScale = 1.0 / obj->segment.trans.scale; i = 0; while (i < 16) { diff --git a/ver/symbols/symbol_addrs.jpn.v79.txt b/ver/symbols/symbol_addrs.jpn.v79.txt index 176960e1..f757db49 100644 --- a/ver/symbols/symbol_addrs.jpn.v79.txt +++ b/ver/symbols/symbol_addrs.jpn.v79.txt @@ -121,16 +121,16 @@ sndp_set_group_volume = 0x80004A60; // audio_vehicle.c .text racer_sound_init = 0x80004B40; racer_sound_update = 0x800050D0; -func_80005254 = 0x80005254; +racer_sound_car = 0x80005254; racer_sound_hovercraft = 0x80005D08; -func_800063EC = 0x800063EC; +racer_sound_plane = 0x800063EC; racer_sound_free = 0x80006AC8; -func_80006BFC = 0x80006BFC; -func_80006FC8 = 0x80006FC8; -sound_vehicle_enable = 0x80007F78; -sound_vehicle_disable = 0x80007F88; -sound_vehicle_check = 0x80007F94; -func_80007FA4 = 0x80007FA4; +racer_sound_doppler_effect = 0x80006BFC; +racer_sound_update_all = 0x80006FC8; +racer_sound_enable = 0x80007F78; +racer_sound_disable = 0x80007F88; +racer_sound_check = 0x80007F94; +log = 0x80007FA4; // audio_spatial.c .text audspat_init = 0x80008040; @@ -2193,8 +2193,8 @@ gNumActiveSounds = 0x800DE054; // audio_vehicle.c .data gVehicleSounds = 0x800DE060; -D_800DC6D4 = 0x800DE064; -D_800DC6D8 = 0x800DE068; +gBackgroundSoundSwapTimer = 0x800DE064; +resetAmbient = 0x800DE068; // audio_spatial.c .data gNumAudioPoints = 0x800DE070; @@ -3562,7 +3562,7 @@ gSoundPlayer = 0x8011B640; gSoundGroupVolume = 0x8011B698; // audio_vehicle .bss -D_80119C30 = 0x8011B6A0; +gBackgroundRacerSounds = 0x8011B6A0; gRacerSound = 0x8011B6A8; gSoundRacerObj = 0x8011B6AC; gSpatialSoundTable = 0x8011B6B0; diff --git a/ver/symbols/symbol_addrs.pal.v77.txt b/ver/symbols/symbol_addrs.pal.v77.txt index 1c349c74..61f788c6 100644 --- a/ver/symbols/symbol_addrs.pal.v77.txt +++ b/ver/symbols/symbol_addrs.pal.v77.txt @@ -121,16 +121,16 @@ sndp_set_group_volume = 0x80004A60; // audio_vehicle.c .text racer_sound_init = 0x80004B40; racer_sound_update = 0x800050D0; -func_80005254 = 0x80005254; +racer_sound_car = 0x80005254; racer_sound_hovercraft = 0x80005D08; -func_800063EC = 0x800063EC; +racer_sound_plane = 0x800063EC; racer_sound_free = 0x80006AC8; -func_80006BFC = 0x80006BFC; -func_80006FC8 = 0x80006FC8; -sound_vehicle_enable = 0x80007F78; -sound_vehicle_disable = 0x80007F88; -sound_vehicle_check = 0x80007F94; -func_80007FA4 = 0x80007FA4; +racer_sound_doppler_effect = 0x80006BFC; +racer_sound_update_all = 0x80006FC8; +racer_sound_enable = 0x80007F78; +racer_sound_disable = 0x80007F88; +racer_sound_check = 0x80007F94; +log = 0x80007FA4; // audio_spatial.c .text audspat_init = 0x80008040; @@ -2097,8 +2097,8 @@ gSoundPlayerPtr = 0x800DC74C; gSoundGlobalVolume = 0x800DC750; gNumActiveSounds = 0x800DC754; gVehicleSounds = 0x800DC760; -D_800DC6D4 = 0x800DC764; -D_800DC6D8 = 0x800DC768; +gBackgroundSoundSwapTimer = 0x800DC764; +resetAmbient = 0x800DC768; gNumAudioPoints = 0x800DC770; gTajChallengeTransition = 0x800DC780; gBalloonCutsceneTransition = 0x800DC788; @@ -3302,7 +3302,7 @@ audDMAMessageQ = 0x80119B80; audDMAMessageBuf = 0x80119B98; gSoundPlayer = 0x80119C60; gSoundGroupVolume = 0x80119CB8; -D_80119C30 = 0x80119CC0; +gBackgroundRacerSounds = 0x80119CC0; gRacerSound = 0x80119CC8; gSoundRacerObj = 0x80119CCC; gSpatialSoundTable = 0x80119CD0; diff --git a/ver/symbols/symbol_addrs.pal.v80.txt b/ver/symbols/symbol_addrs.pal.v80.txt index bcdf426a..9202e57f 100644 --- a/ver/symbols/symbol_addrs.pal.v80.txt +++ b/ver/symbols/symbol_addrs.pal.v80.txt @@ -121,16 +121,16 @@ sndp_set_group_volume = 0x80004A60; // audio_vehicle.c .text racer_sound_init = 0x80004B40; racer_sound_update = 0x800050D0; -func_80005254 = 0x80005254; +racer_sound_car = 0x80005254; racer_sound_hovercraft = 0x80005D08; -func_800063EC = 0x800063EC; +racer_sound_plane = 0x800063EC; racer_sound_free = 0x80006AC8; -func_80006BFC = 0x80006BFC; -func_80006FC8 = 0x80006FC8; -sound_vehicle_enable = 0x80007F78; -sound_vehicle_disable = 0x80007F88; -sound_vehicle_check = 0x80007F94; -func_80007FA4 = 0x80007FA4; +racer_sound_doppler_effect = 0x80006BFC; +racer_sound_update_all = 0x80006FC8; +racer_sound_enable = 0x80007F78; +racer_sound_disable = 0x80007F88; +racer_sound_check = 0x80007F94; +log = 0x80007FA4; // audio_spatial.c .text audspat_init = 0x80008040; @@ -2024,8 +2024,8 @@ gSoundPlayerPtr = 0x800DCCBC; gSoundGlobalVolume = 0x800DCCC0; gNumActiveSounds = 0x800DCCC4; gVehicleSounds = 0x800DCCD0; -D_800DC6D4 = 0x800DCCD4; -D_800DC6D8 = 0x800DCCD8; +gBackgroundSoundSwapTimer = 0x800DCCD4; +resetAmbient = 0x800DCCD8; gNumAudioPoints = 0x800DCCE0; gTajChallengeTransition = 0x800DCCF0; gBalloonCutsceneTransition = 0x800DCCF8; @@ -3232,7 +3232,7 @@ audDMAMessageQ = 0x8011A100; audDMAMessageBuf = 0x8011A118; gSoundPlayer = 0x8011A1E0; gSoundGroupVolume = 0x8011A238; -D_80119C30 = 0x8011A240; +gBackgroundRacerSounds = 0x8011A240; gRacerSound = 0x8011A248; gSoundRacerObj = 0x8011A24C; gSpatialSoundTable = 0x8011A250; diff --git a/ver/symbols/symbol_addrs.us.v77.txt b/ver/symbols/symbol_addrs.us.v77.txt index fde577cb..1aca4ebb 100644 --- a/ver/symbols/symbol_addrs.us.v77.txt +++ b/ver/symbols/symbol_addrs.us.v77.txt @@ -121,16 +121,16 @@ sndp_set_group_volume = 0x80004A60; // audio_vehicle.c .text racer_sound_init = 0x80004B40; racer_sound_update = 0x800050D0; -func_80005254 = 0x80005254; +racer_sound_car = 0x80005254; racer_sound_hovercraft = 0x80005D08; -func_800063EC = 0x800063EC; +racer_sound_plane = 0x800063EC; racer_sound_free = 0x80006AC8; -func_80006BFC = 0x80006BFC; -func_80006FC8 = 0x80006FC8; -sound_vehicle_enable = 0x80007F78; -sound_vehicle_disable = 0x80007F88; -sound_vehicle_check = 0x80007F94; -func_80007FA4 = 0x80007FA4; +racer_sound_doppler_effect = 0x80006BFC; +racer_sound_update_all = 0x80006FC8; +racer_sound_enable = 0x80007F78; +racer_sound_disable = 0x80007F88; +racer_sound_check = 0x80007F94; +log = 0x80007FA4; // audio_spatial.c .text audspat_init = 0x80008040; @@ -2188,8 +2188,8 @@ gNumActiveSounds = 0x800DC6C4; // audio_vehicle.c .data gVehicleSounds = 0x800DC6D0; -D_800DC6D4 = 0x800DC6D4; -D_800DC6D8 = 0x800DC6D8; +gBackgroundSoundSwapTimer = 0x800DC6D4; +resetAmbient = 0x800DC6D8; // audio_spatial.c .data gNumAudioPoints = 0x800DC6E0; @@ -3675,7 +3675,7 @@ gSoundPlayer = 0x80119BD0; gSoundGroupVolume = 0x80119C28; // audio_vehicle .bss -D_80119C30 = 0x80119C30; +gBackgroundRacerSounds = 0x80119C30; gRacerSound = 0x80119C38; gSoundRacerObj = 0x80119C3C; diff --git a/ver/symbols/symbol_addrs.us.v80.txt b/ver/symbols/symbol_addrs.us.v80.txt index 98e1eb15..a96b74f6 100644 --- a/ver/symbols/symbol_addrs.us.v80.txt +++ b/ver/symbols/symbol_addrs.us.v80.txt @@ -121,16 +121,16 @@ sndp_set_group_volume = 0x80004A60; // audio_vehicle.c .text racer_sound_init = 0x80004B40; racer_sound_update = 0x800050D0; -func_80005254 = 0x80005254; +racer_sound_car = 0x80005254; racer_sound_hovercraft = 0x80005D08; -func_800063EC = 0x800063EC; +racer_sound_plane = 0x800063EC; racer_sound_free = 0x80006AC8; -func_80006BFC = 0x80006BFC; -func_80006FC8 = 0x80006FC8; -sound_vehicle_enable = 0x80007F78; -sound_vehicle_disable = 0x80007F88; -sound_vehicle_check = 0x80007F94; -func_80007FA4 = 0x80007FA4; +racer_sound_doppler_effect = 0x80006BFC; +racer_sound_update_all = 0x80006FC8; +racer_sound_enable = 0x80007F78; +racer_sound_disable = 0x80007F88; +racer_sound_check = 0x80007F94; +log = 0x80007FA4; // audio_spatial.c .text audspat_init = 0x80008040; @@ -2021,8 +2021,8 @@ gSoundPlayerPtr = 0x800DCC2C; gSoundGlobalVolume = 0x800DCC30; gNumActiveSounds = 0x800DCC34; gVehicleSounds = 0x800DCC40; -D_800DC6D4 = 0x800DCC44; -D_800DC6D8 = 0x800DCC48; +gBackgroundSoundSwapTimer = 0x800DCC44; +resetAmbient = 0x800DCC48; gNumAudioPoints = 0x800DCC50; gTajChallengeTransition = 0x800DCC60; gBalloonCutsceneTransition = 0x800DCC68; @@ -3228,7 +3228,7 @@ audDMAMessageQ = 0x8011A070; audDMAMessageBuf = 0x8011A088; gSoundPlayer = 0x8011A150; gSoundGroupVolume = 0x8011A1A8; -D_80119C30 = 0x8011A1B0; +gBackgroundRacerSounds = 0x8011A1B0; gRacerSound = 0x8011A1B8; gSoundRacerObj = 0x8011A1BC; gSpatialSoundTable = 0x8011A1C0;