From a28aeb69385ea49db0269461ebad90a96ada0ef3 Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Sun, 24 Aug 2025 13:17:58 +0200 Subject: [PATCH] feat: sound effects --- C/fps/Makefile | 4 +-- C/fps/README.md | 5 +-- C/fps/main.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 4 deletions(-) diff --git a/C/fps/Makefile b/C/fps/Makefile index dd94a9d..755857c 100644 --- a/C/fps/Makefile +++ b/C/fps/Makefile @@ -2,8 +2,8 @@ # Targets: build (default), run, clean CC := gcc -CFLAGS := -O2 -Wall -Wextra -Wno-missing-field-initializers -std=c11 -LDFLAGS := -lglut -lGLU -lGL -lm +CFLAGS := -O2 -Wall -Wextra -Wno-missing-field-initializers -std=c11 $(shell pkg-config --cflags sdl2 2>/dev/null) +LDFLAGS := -lglut -lGLU -lGL -lm $(shell pkg-config --libs sdl2 2>/dev/null) SRC := main.c BIN := fps_demo diff --git a/C/fps/README.md b/C/fps/README.md index afb63c5..d89404a 100644 --- a/C/fps/README.md +++ b/C/fps/README.md @@ -8,12 +8,12 @@ A tiny first-person demo using legacy OpenGL (compat) and FreeGLUT: ## Build -Requires development packages for OpenGL, GLU, and FreeGLUT. +Requires development packages for OpenGL, GLU, FreeGLUT, and SDL2 (for audio). On Debian/Ubuntu: ```sh sudo apt-get update -sudo apt-get install -y build-essential freeglut3-dev +sudo apt-get install -y build-essential freeglut3-dev libsdl2-dev pkg-config ``` Then build and run: @@ -29,3 +29,4 @@ If your distro uses different package names, install the equivalents of: ## Notes - This uses old-school fixed-function OpenGL for simplicity and broad compatibility. - Mouse is confined via glutWarpPointer; press M if you need to release it. +- SDL2 is used only for simple procedurally generated sound effects (shoot, hit, game over). diff --git a/C/fps/main.c b/C/fps/main.c index ecbe6b6..cae2409 100644 --- a/C/fps/main.c +++ b/C/fps/main.c @@ -12,6 +12,7 @@ #include #include #include +#include #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -84,6 +85,97 @@ static vec3 cam_right() return v3_norm(v3_cross(cam_front(), v3(0,1,0))); } +// -------- Audio (SDL2) -------- +static SDL_AudioDeviceID g_audio_dev = 0; +static SDL_AudioSpec g_audio_have; +static bool g_audio_ok = false; + +static void audio_cleanup(void) +{ + if (g_audio_dev) { + SDL_ClearQueuedAudio(g_audio_dev); + SDL_CloseAudioDevice(g_audio_dev); + g_audio_dev = 0; + } + if (g_audio_ok) { + SDL_QuitSubSystem(SDL_INIT_AUDIO); + g_audio_ok = false; + } +} + +static void audio_init(void) +{ + if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) { + fprintf(stderr, "SDL audio init failed: %s\n", SDL_GetError()); + return; + } + SDL_AudioSpec want; + SDL_zero(want); + want.freq = 48000; + want.format = AUDIO_F32SYS; + want.channels = 1; + want.samples = 1024; + g_audio_dev = SDL_OpenAudioDevice(NULL, 0, &want, &g_audio_have, 0); + if (!g_audio_dev) { + fprintf(stderr, "SDL_OpenAudioDevice failed: %s\n", SDL_GetError()); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + return; + } + SDL_PauseAudioDevice(g_audio_dev, 0); + g_audio_ok = true; + atexit(audio_cleanup); +} + +static void audio_queue_samples(const float* data, int frames) +{ + if (!g_audio_ok) return; + int bytes = frames * (int)sizeof(float); + SDL_QueueAudio(g_audio_dev, data, bytes); +} + +static void audio_play_tone(float freq, float duration, float vol) +{ + if (!g_audio_ok) return; + int sr = g_audio_have.freq ? g_audio_have.freq : 48000; + int frames = (int)(duration * sr); + if (frames <= 0) return; + float* buf = (float*)malloc((size_t)frames * sizeof(float)); + if (!buf) return; + float phase = 0.0f; + float dp = 2.0f * (float)M_PI * freq / (float)sr; + for (int i=0; i= 0) { // remove hit target (swap remove) g_targets[best_i] = g_targets[g_target_count-1]; g_target_count--; g_score++; + audio_play_tone(600.0f, 0.08f, 0.35f); // hit } } @@ -309,6 +403,7 @@ static void update(float dt) if (dist2 <= reach*reach) { g_state = GAME_OVER; glutSetCursor(GLUT_CURSOR_LEFT_ARROW); + audio_play_sweep(400.0f, 120.0f, 0.5f, 0.5f); // game over break; } } @@ -433,6 +528,7 @@ int main(int argc, char** argv) glutCreateWindow("FPS Demo"); init_gl(); + audio_init(); glutDisplayFunc(display); glutIdleFunc(idle);