Add a Sound
In short
There are no audio files: every sound is generated in code at startup. Build the clip in
SoundBankfromAudioSynthpieces (tones, noise, filters, envelopes), then play it inGameAudiofrom aGameEventshandler, so gameplay code never touches audio.
Steps
- Build the clip. In
Assets/_Project/Scripts/Audio/SoundBank.cs:- add a property:
public AudioClip Coin { get; private set; } - set it in the constructor:
Coin = BuildCoin(); - write the builder from
AudioSynthpieces. The coin is a typical small one:
static AudioClip BuildCoin() { var a = AudioSynth.Tone(1760f, 0.09f, 0.5f, Waveform.Square); AudioSynth.ExpDecay(a, 30f); var b = AudioSynth.Tone(2637f, 0.22f, 0.5f, Waveform.Square); AudioSynth.ExpDecay(b, 14f); var mix = AudioSynth.Silence(0.32f); AudioSynth.MixInto(mix, a, 0f); AudioSynth.MixInto(mix, b, 0.08f); AudioSynth.LowPass(mix, 0.5f); AudioSynth.Normalize(mix, 0.6f); return AudioSynth.ToClip("Coin", mix); }AudioSynth(inAudio/AudioSynth.cs) hasTone,Organ,Brass,Sweep,Voices(crowd),Noise,Silence,LowPass,LowPassSweep,HighPass,Envelope,ExpDecay,Gain,Wobble,Mix,MixInto,MakeLoop,Normalize,Clamp,Samples,NoteHzandToClip. Since #40 and #42 some clips are built inGameAudioitself instead (BuildImpact,BuildFireworkBang,BuildSadTrombone,BuildCountTick,BuildRiser, kept in fields set inAwake). Either place works;SoundBankkeeps the shared ones. Pass a fixed seed toNoise/Voicesso the sound is the same every launch. - add a property:
- Play it in
Assets/_Project/Scripts/Audio/GameAudio.cs:- On a game event: in an existing handler (
OnSwingResolved,OnHitLanded,OnCountChanged,OnRoundFinished,OnRunEnded,OnScoreboardHit…) callPlay(_bank.MySound, volume, pitch). For a new event, add it toCore/GameEvents.cs(event,Raise...method, and a line inClearAll), raise it from the gameplay code, and subscribe inGameAudio.OnEnable/ unsubscribe inOnDisable. - From the UI or a cutscene: add a static one-liner like the existing ones and call it from the view or
director (the cutscenes call
GameAudio.Impact,Whoosh,Fanfare,FireworkBang,SadTrombone; the hit counter callsCounterTick,CounterDing,Gone,StackHit,CounterSlam,CounterStamp):
public static void Coin() => Instance?.Play(Instance._bank.Coin, 0.7f); - On a game event: in an existing handler (
Check it works
Press Play and trigger it. The SOUND slider (settings) scales every effect through SfxVolume; check it at a
low value too. No self-test covers audio.
Gotchas
- Clips are built once, in the
SoundBankconstructor whenGameAudiowakes. A long or complex sound adds to startup time. Playuses one shared one-shot source and sets its pitch per call. The hit counter’s ticks use a second source (_counter, viaPlayCounter) so their rising pitch doesn’t bend the cheers playing at the same time.- The organ also goes quiet during the match intro and the end scenes (
OnStatetreatsIntroandOutrolike an at-bat). - Pausing silences the field (
AudioListener.pause); only the organ ignores the pause. A UI sound played while paused will not be heard. - The style is deliberate (see the
SoundBanksummary): nothing loops or hisses, and the crowd only reacts to plays. - The GREEN sound is generated like the rest:
SoundBank.CrackGreen(picked byCrackForwhen the swing is green) plus a small cheer that grows with the streak, both inGameAudio.OnSwingResolved. The README’sGreenFeedback.GreenClipno longer exists;UI/GreenFeedbackonly shakes the camera.
Related
- Audio: how game audio is organised
- Game Events: the events to hook
- Add a Setting: volume sliders live in settings
- Hit Show · Cutscenes: the newest sound users