Initial commit

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shweetandClaude Opus 5.5 committed 2026-11-08 01:30:33 -05:00
commit 2007fb7edc
200 files changed
+27710

No files matched your search

+170
View File
@@ -0,0 +1,170 @@
#include "audio.h"
#include "common.h"
#include <SDL3/SDL.h>
#include <stb_vorbis.c>
constexpr float PITCH_VARIANCE = 0.06f;
constexpr Uint64 SOUND_GAP = 40 * SDL_NS_PER_MS;
constexpr const char* SOUND_NAMES[SOUND_COUNT] = {
"beam",
"blast",
"boomerang",
"boomerang_heavy",
"bounce",
"bow",
"bow_heavy",
"break",
"cast",
"charge",
"chat",
"crawl",
"dash",
"death",
"detonate",
"detonate_empty",
"duck",
"echo",
"equip",
"explosion",
"fall",
"finish",
"fireball",
"flail",
"flail_heavy",
"flail_land",
"flame",
"grapple",
"grapple_heavy",
"hit_blunt",
"hit_blunt_heavy",
"hit_bullet",
"hit_bullet_heavy",
"hit_energy",
"hit_energy_heavy",
"hit_explosive",
"hit_explosive_heavy",
"hit_fire",
"hit_fire_heavy",
"hit_lash",
"hit_lash_heavy",
"hit_magic",
"hit_magic_heavy",
"hit_pierce",
"hit_pierce_heavy",
"hit_slash",
"hit_slash_heavy",
"impact_arrow",
"impact_blaster",
"impact_boomerang",
"impact_bullet",
"impact_mine",
"jump",
"land",
"latch",
"level_down",
"level_up",
"mine",
"poke",
"poke_heavy",
"pound",
"punch",
"ready",
"ricochet",
"rocket",
"rocket_heavy",
"roll",
"select",
"shotgun",
"shotgun_heavy",
"slam",
"slash",
"slash_heavy",
"step",
"swap",
"swing",
"swing_heavy",
"teleport",
"teleport_warp",
"unduck",
"unequip",
"uppercut",
"uzi",
"uzi_heavy",
"whip",
"whip_heavy",
"wisp",
"zap",
};
void Audio::init()
{
if (SDL_InitSubSystem(SDL_INIT_AUDIO))
device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, nullptr);
if (!device)
{
SDL_Log("Failed to open audio: %s", SDL_GetError());
return;
}
for (int i = 0; i < SOUND_COUNT; i++)
{
std::string path = path_get("sfx/") + SOUND_NAMES[i] + ".ogg";
Sound& sound = sounds[i];
sound.frames = stb_vorbis_decode_filename(path.c_str(), &sound.channels, &sound.rate, &sound.samples);
if (sound.frames <= 0)
SDL_Log("Failed to load %s", path.c_str());
}
SDL_AudioSpec deviceSpec = {};
SDL_GetAudioDeviceFormat(device, &deviceSpec, nullptr);
for (SDL_AudioStream*& voice : voices)
{
voice = SDL_CreateAudioStream(&deviceSpec, &deviceSpec);
SDL_BindAudioStream(device, voice);
}
}
// Plays a sound with a slight random pitch and returns the voice used, or -1 if it was skipped.
int Audio::play(SoundId id)
{
if (id == SOUND_NONE)
return -1;
Sound& sound = sounds[id];
Uint64 now = SDL_GetTicksNS();
if (!device || sound.frames <= 0 || isMuted || now - sound.played < SOUND_GAP)
return -1;
sound.played = now;
int voice = voiceNext;
for (int i = 0; i < VOICE_COUNT; i++)
{
if (SDL_GetAudioStreamQueued(voices[i]) == 0)
{
voice = i;
break;
}
}
voiceNext = (voice + 1) % VOICE_COUNT;
SDL_AudioStream* stream = voices[voice];
SDL_AudioSpec spec = {SDL_AUDIO_S16, sound.channels, sound.rate};
SDL_ClearAudioStream(stream);
SDL_SetAudioStreamFormat(stream, &spec, nullptr);
SDL_SetAudioStreamFrequencyRatio(stream, random_get(1 - PITCH_VARIANCE, 1 + PITCH_VARIANCE));
SDL_PutAudioStreamData(stream, sound.samples, sound.frames * sound.channels * sizeof(short));
return voice;
}
// Sets the volume of everything played, from silent at 0 to full at 1.
void Audio::gain_set(float gain)
{
if (device)
SDL_SetAudioDeviceGain(device, gain);
}
void Audio::stop(int voice)
{
if (voice >= 0)
SDL_ClearAudioStream(voices[voice]);
}