diff --git a/assets/audio/rx7_rev_loop.ogg b/assets/audio/rx7_rev_loop.ogg index 354916d..a8e8360 100644 Binary files a/assets/audio/rx7_rev_loop.ogg and b/assets/audio/rx7_rev_loop.ogg differ diff --git a/assets/audio/rx7_whistle_loop.ogg b/assets/audio/rx7_whistle_loop.ogg new file mode 100644 index 0000000..6b58fe0 Binary files /dev/null and b/assets/audio/rx7_whistle_loop.ogg differ diff --git a/docs/ROTARY_SOUND.md b/docs/ROTARY_SOUND.md index b65e508..24138f9 100644 --- a/docs/ROTARY_SOUND.md +++ b/docs/ROTARY_SOUND.md @@ -1,23 +1,27 @@ ## Status: loops are BUILT ✅ — awaiting Studio upload -Real 13B loops were extracted from the owner's own drive footage -(`/mnt/user/data/c-finished-videos/2026-07-10/`, same car) and processed on the -workstation. They live at: +Real 13B loops extracted from the owner's own footage. **v2**: rev + turbo +whistle now come from the action-cam library +(`/mnt/user/data/b-action-cam-footage/clipchamp/`, 99 GB scanned — same car), +which captured the turbo + exhaust together far better than the first source. - `assets/audio/rx7_idle_loop.ogg` — 15.9 s steady idle (~99 Hz fundamental, - scanned as the most tonally stable stretch of the session; seam jump 0.001) -- `assets/audio/rx7_rev_loop.ogg` — 7.4 s held higher-RPM pull (~105 Hz, - louder section; seam jump 0.005) + from the 2026-07-10 session; seam jump 0.001) +- `assets/audio/rx7_rev_loop.ogg` — 7.9 s whistle-rich highway pull (~124 Hz, + from 20260510-Return..., window 985-993 s: 0.0 Hz pitch drift across 8 s, + turbo whistle ~1.7 kHz riding +33 dB over the band; seam jump 0.001) +- `assets/audio/rx7_whistle_loop.ogg` — the SAME pull high-passed at 1.2 kHz: + isolated turbo whistle, layered in-game on top of the rev loop and faded + in/up with "boost" (throttle held at speed) for the authentic spool sound - Masters (`.wav` + `.ogg`) mirrored to the NAS: `.../001-1993 Mazda RX-7/sound/` -**Remaining (owner, in Studio): upload the two `.ogg` files** (Asset Manager → -Import, or Creator Dashboard → Audio), wait for moderation, then paste the two +**Remaining (owner, in Studio): upload the three `.ogg` files** (Asset Manager → +Import, or Creator Dashboard → Audio), wait for moderation, then paste the three asset IDs into `CAR_SOUNDS.rx7_fc` in `src/client/SoundController.luau`. -If a longer/angrier rev is wanted later, more source material exists in the -other sessions under `c-finished-videos/` — the extraction is repeatable -(method below). +More source material exists in the other clipchamp sessions — the extraction is +repeatable (method below). --- diff --git a/src/client/SoundController.luau b/src/client/SoundController.luau index 98106e7..c4b8775 100644 --- a/src/client/SoundController.luau +++ b/src/client/SoundController.luau @@ -34,19 +34,26 @@ local player = Players.LocalPlayer local SoundController = {} -type EngineSounds = { Idle: string, Rev: string } +type EngineSounds = { Idle: string, Rev: string, Whistle: string? } -- Default (generic) sounds -------------------------------------------------- local DEFAULT_SOUNDS: EngineSounds = { Idle = "rbxassetid://80317022777602", -- Roblox Resources engine loop Rev = "rbxassetid://80317022777602", -- same loop until real rev samples exist + Whistle = nil, -- most cars have no turbo layer } local SQUEAL_ID = "rbxassetid://9120399077" -- ProSoundEffects tyre squeal --- Per-car engine sounds. Fill rx7_fc with the owner's real 13B recordings --- once uploaded (docs/ROTARY_SOUND.md). Cars not listed use DEFAULT_SOUNDS. +-- Per-car engine sounds. The rx7_fc loops are cut from the owner's REAL FD +-- footage (docs/ROTARY_SOUND.md): idle + whistle-rich rev + an isolated +-- >1.2kHz turbo whistle layer that rides boost. Fill the IDs after the +-- Studio upload of assets/audio/*.ogg. local CAR_SOUNDS: { [string]: EngineSounds } = { - -- rx7_fc = { Idle = "rbxassetid://<13B_IDLE>", Rev = "rbxassetid://<13B_REV>" }, + -- rx7_fc = { + -- Idle = "rbxassetid://", + -- Rev = "rbxassetid://", + -- Whistle = "rbxassetid://", + -- }, } -- Tunables -------------------------------------------------------------------- @@ -63,6 +70,13 @@ local SLIP_START = 14 -- studs/sec lateral slip where squeal begins local SLIP_FULL = 34 -- lateral slip for max squeal volume local SQUEAL_MAX_VOLUME = 0.5 local RESPONSIVENESS = 8 -- volume/pitch smoothing (1/sec) +-- Turbo whistle layer (cars with Whistle set): rides "boost" = throttle +-- held at speed. Fades in above BOOST_START speedFrac when on throttle. +local WHISTLE_MAX_VOLUME = 0.45 +local BOOST_START = 0.25 -- speedFrac where boost can begin +local BOOST_FULL = 0.8 -- speedFrac of max whistle +local WHISTLE_PITCH_MIN = 0.9 +local WHISTLE_PITCH_MAX = 1.35 local heartbeatConn: RBXScriptConnection? = nil local seatedConn: RBXScriptConnection? = nil @@ -104,9 +118,16 @@ local function startAudio(seat: VehicleSeat) local idle = makeSound("EngineIdle", engineSet.Idle, ENGINE_BASE_VOLUME, bodyPart) local rev = makeSound("EngineRev", engineSet.Rev, 0, bodyPart) local squeal = makeSound("TyreSqueal", SQUEAL_ID, 0, bodyPart) + local whistle: Sound? = nil + if engineSet.Whistle then + whistle = makeSound("TurboWhistle", engineSet.Whistle, 0, bodyPart) + end idle:Play() rev:Play() squeal:Play() -- all loops run constantly; we fade volumes (no start/stop pops) + if whistle then + whistle:Play() + end heartbeatConn = RunService.Heartbeat:Connect(function(dt) if not bodyPart.Parent then @@ -138,6 +159,16 @@ local function startAudio(seat: VehicleSeat) local braking = (seat.ThrottleFloat == 0 and speed > tuning.MaxSpeed * 0.5) and 0.25 or 0 local squealTarget = math.max(slipFrac, braking) * SQUEAL_MAX_VOLUME squeal.Volume += (squealTarget - squeal.Volume) * a + + -- Turbo whistle: spools with throttle held at speed ("on boost"). + if whistle then + local boost = math.clamp((speedFrac - BOOST_START) / (BOOST_FULL - BOOST_START), 0, 1) + * math.abs(seat.ThrottleFloat) + local whistleVolTarget = WHISTLE_MAX_VOLUME * boost + local whistlePitchTarget = WHISTLE_PITCH_MIN + (WHISTLE_PITCH_MAX - WHISTLE_PITCH_MIN) * boost + whistle.Volume += (whistleVolTarget - whistle.Volume) * a + whistle.PlaybackSpeed += (whistlePitchTarget - whistle.PlaybackSpeed) * a + end end) end