Use this skill when we need to generate sounds or run sound engineering
You are a sound effects generation agent for a multiplayer racing game. Your job is to create audio files (.mp3 or .wav) for game sound effects using programmatic audio synthesis.
Before generating sounds, ensure these Python packages are installed:
pip install numpy scipy pydub
For MP3 export, also ensure ffmpeg is available:
brew install ffmpeg # macOS
Use Python with NumPy/SciPy for audio synthesis. The general pattern:
import numpy as np
from scipy.io import wavfile
from pydub import AudioSegment
import os
SAMPLE_RATE = 44100
def generate_sound(samples, filename):
"""Save samples to WAV, then convert to MP3"""
# Normalize to 16-bit range
samples = np.clip(samples, -1, 1)
samples_16bit = (samples * 32767).astype(np.int16)
wav_path = filename.replace('.mp3', '.wav')
wavfile.write(wav_path, SAMPLE_RATE, samples_16bit)
# Convert to MP3
if filename.endswith('.mp3'):
audio = AudioSegment.from_wav(wav_path)
audio.export(filename, format='mp3')
os.remove(wav_path)
File: static/audio/sfx/engine_idle.mp3
File: static/audio/sfx/engine_rev.mp3
def generate_engine_sound(base_freq=80, duration=2.0):
t = np.linspace(0, duration, int(SAMPLE_RATE * duration))
# Base frequency with slight wobble
wobble = 1 + 0.02 * np.sin(2 * np.pi * 4 * t)
# Multiple harmonics for engine character
sound = 0.5 * np.sin(2 * np.pi * base_freq * wobble * t)
sound += 0.3 * np.sin(2 * np.pi * base_freq * 2 * wobble * t)
sound += 0.15 * np.sin(2 * np.pi * base_freq * 3 * wobble * t)
# Add some noise for texture
noise = np.random.uniform(-0.1, 0.1, len(t))
sound += noise * 0.1
# Fade ends for seamless looping
fade_len = int(SAMPLE_RATE * 0.05)
sound[:fade_len] *= np.linspace(0, 1, fade_len)
sound[-fade_len:] *= np.linspace(1, 0, fade_len)
return sound
File: static/audio/sfx/collision_soft.mp3
File: static/audio/sfx/collision_hard.mp3
def generate_collision(intensity='soft'):
duration = 0.3 if intensity == 'soft' else 0.5
t = np.linspace(0, duration, int(SAMPLE_RATE * duration))
# Impact envelope (quick attack, decay)
envelope = np.exp(-t * (20 if intensity == 'soft' else 12))
# Low frequency thump
thump = np.sin(2 * np.pi * 60 * t) * envelope
# Noise burst for crash texture
noise = np.random.uniform(-1, 1, len(t)) * envelope
noise_filtered = noise * (0.3 if intensity == 'soft' else 0.5)
# Metallic ring for hard collision
if intensity == 'hard':
ring = np.sin(2 * np.pi * 800 * t) * envelope * 0.2
thump += ring
sound = thump * 0.7 + noise_filtered * 0.3
return sound
File: static/audio/sfx/tire_screech.mp3
def generate_tire_screech(duration=1.5):
t = np.linspace(0, duration, int(SAMPLE_RATE * duration))
# Filtered noise for screech
noise = np.random.uniform(-1, 1, len(t))
# High-pass filter effect (simple differencing)
screech = np.diff(noise, prepend=noise[0]) * 5
# Add some pitch modulation
mod = np.sin(2 * np.pi * 15 * t)
pitch = 2000 + 500 * mod
carrier = np.sin(2 * np.pi * np.cumsum(pitch / SAMPLE_RATE))
sound = screech * 0.3 + carrier * 0.2
# Envelope
envelope = np.ones(len(t))
fade = int(0.1 * SAMPLE_RATE)
envelope[:fade] *= np.linspace(0, 1, fade)
envelope[-fade:] *= np.linspace(1, 0, fade)
return sound * envelope
File: static/audio/sfx/player_join.mp3
File: static/audio/sfx/button_click.mp3
def generate_ui_chime():
duration = 0.4
t = np.linspace(0, duration, int(SAMPLE_RATE * duration))
# Two-note rising chime
freq1, freq2 = 523, 659 # C5, E5
note1 = np.sin(2 * np.pi * freq1 * t[:len(t)//2])
note2 = np.sin(2 * np.pi * freq2 * t[len(t)//2:])
sound = np.concatenate([note1, note2])
# Envelope
envelope = np.exp(-t * 5)
return sound * envelope * 0.5
def generate_button_click():
duration = 0.08
t = np.linspace(0, duration, int(SAMPLE_RATE * duration))
# Quick pop
freq = 1000
sound = np.sin(2 * np.pi * freq * t)
envelope = np.exp(-t * 50)
return sound * envelope * 0.3
Place all generated sounds in: static/audio/sfx/
For each sound:
After generating sounds, they need to be loaded in audioManager.js. Add them to the loadSounds() method:
const sfxSounds = {
engine_idle: '/static/audio/sfx/engine_idle.mp3',
engine_rev: '/static/audio/sfx/engine_rev.mp3',
collision_soft: '/static/audio/sfx/collision_soft.mp3',
collision_hard: '/static/audio/sfx/collision_hard.mp3',
tire_screech: '/static/audio/sfx/tire_screech.mp3',
player_join: '/static/audio/sfx/player_join.mp3',
button_click: '/static/audio/sfx/button_click.mp3'
};
For the in-game engine that changes with car speed, the audioManager needs:
The host.js game loop should call:
audioManager.updateEngineSound(carSpeed, isAccelerating);
This requires implementing the engine sound methods in audioManager.js.