RX-7 audio v2: turbo whistle + exhaust from the action-cam library
CI / quality (push) Successful in 1m4s

- Scanned b-action-cam-footage/clipchamp (99GB, 5 videos of the FD):
  extracted audio NAS-side via linuxserver/ffmpeg container (stream-copy),
  scanned 69min return drive per-second for engine tonality + whistle
  prominence (1.5-9kHz peak vs band median)
- New rev loop: 985-993s highway pull — 0.0Hz pitch drift over 8s,
  whistle ~1.7kHz at +33dB, exhaust + turbo captured together (seam 0.001)
- New whistle-only loop: same pull high-passed 1.2kHz — isolated spool
- SoundController: optional per-car Whistle layer that rides boost
  (throttle held at speed): fades in past 25% speed, pitch 0.9->1.35
- ROTARY_SOUND.md updated; three .ogg uploads needed in Studio now
This commit is contained in:
2026-07-22 02:26:45 -04:00
parent 1891f3f11d
commit dae30fd22e
4 changed files with 50 additions and 15 deletions
Binary file not shown.
Binary file not shown.
+15 -11
View File
@@ -1,23 +1,27 @@
## Status: loops are BUILT ✅ — awaiting Studio upload ## Status: loops are BUILT ✅ — awaiting Studio upload
Real 13B loops were extracted from the owner's own drive footage Real 13B loops extracted from the owner's own footage. **v2**: rev + turbo
(`/mnt/user/data/c-finished-videos/2026-07-10/`, same car) and processed on the whistle now come from the action-cam library
workstation. They live at: (`/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, - `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) from the 2026-07-10 session; seam jump 0.001)
- `assets/audio/rx7_rev_loop.ogg` — 7.4 s held higher-RPM pull (~105 Hz, - `assets/audio/rx7_rev_loop.ogg` — 7.9 s whistle-rich highway pull (~124 Hz,
louder section; seam jump 0.005) 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: - Masters (`.wav` + `.ogg`) mirrored to the NAS:
`.../001-1993 Mazda RX-7/sound/` `.../001-1993 Mazda RX-7/sound/`
**Remaining (owner, in Studio): upload the two `.ogg` files** (Asset Manager → **Remaining (owner, in Studio): upload the three `.ogg` files** (Asset Manager →
Import, or Creator Dashboard → Audio), wait for moderation, then paste the two Import, or Creator Dashboard → Audio), wait for moderation, then paste the three
asset IDs into `CAR_SOUNDS.rx7_fc` in `src/client/SoundController.luau`. 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 More source material exists in the other clipchamp sessions — the extraction is
other sessions under `c-finished-videos/` — the extraction is repeatable repeatable (method below).
(method below).
--- ---
+35 -4
View File
@@ -34,19 +34,26 @@ local player = Players.LocalPlayer
local SoundController = {} local SoundController = {}
type EngineSounds = { Idle: string, Rev: string } type EngineSounds = { Idle: string, Rev: string, Whistle: string? }
-- Default (generic) sounds -------------------------------------------------- -- Default (generic) sounds --------------------------------------------------
local DEFAULT_SOUNDS: EngineSounds = { local DEFAULT_SOUNDS: EngineSounds = {
Idle = "rbxassetid://80317022777602", -- Roblox Resources engine loop Idle = "rbxassetid://80317022777602", -- Roblox Resources engine loop
Rev = "rbxassetid://80317022777602", -- same loop until real rev samples exist 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 local SQUEAL_ID = "rbxassetid://9120399077" -- ProSoundEffects tyre squeal
-- Per-car engine sounds. Fill rx7_fc with the owner's real 13B recordings -- Per-car engine sounds. The rx7_fc loops are cut from the owner's REAL FD
-- once uploaded (docs/ROTARY_SOUND.md). Cars not listed use DEFAULT_SOUNDS. -- 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 } = { local CAR_SOUNDS: { [string]: EngineSounds } = {
-- rx7_fc = { Idle = "rbxassetid://<13B_IDLE>", Rev = "rbxassetid://<13B_REV>" }, -- rx7_fc = {
-- Idle = "rbxassetid://<rx7_idle_loop>",
-- Rev = "rbxassetid://<rx7_rev_loop>",
-- Whistle = "rbxassetid://<rx7_whistle_loop>",
-- },
} }
-- Tunables -------------------------------------------------------------------- -- 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 SLIP_FULL = 34 -- lateral slip for max squeal volume
local SQUEAL_MAX_VOLUME = 0.5 local SQUEAL_MAX_VOLUME = 0.5
local RESPONSIVENESS = 8 -- volume/pitch smoothing (1/sec) 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 heartbeatConn: RBXScriptConnection? = nil
local seatedConn: 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 idle = makeSound("EngineIdle", engineSet.Idle, ENGINE_BASE_VOLUME, bodyPart)
local rev = makeSound("EngineRev", engineSet.Rev, 0, bodyPart) local rev = makeSound("EngineRev", engineSet.Rev, 0, bodyPart)
local squeal = makeSound("TyreSqueal", SQUEAL_ID, 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() idle:Play()
rev:Play() rev:Play()
squeal:Play() -- all loops run constantly; we fade volumes (no start/stop pops) 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) heartbeatConn = RunService.Heartbeat:Connect(function(dt)
if not bodyPart.Parent then 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 braking = (seat.ThrottleFloat == 0 and speed > tuning.MaxSpeed * 0.5) and 0.25 or 0
local squealTarget = math.max(slipFrac, braking) * SQUEAL_MAX_VOLUME local squealTarget = math.max(slipFrac, braking) * SQUEAL_MAX_VOLUME
squeal.Volume += (squealTarget - squeal.Volume) * a 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)
end end