mirror of
https://github.com/kuhyx/testsAndMisc-archive.git
synced 2026-07-04 15:43:11 +02:00
feat: sound effects
This commit is contained in:
parent
74120f2cde
commit
41fa4c5d04
@ -2,8 +2,8 @@
|
|||||||
# Targets: build (default), run, clean
|
# Targets: build (default), run, clean
|
||||||
|
|
||||||
CC := gcc
|
CC := gcc
|
||||||
CFLAGS := -O2 -Wall -Wextra -Wno-missing-field-initializers -std=c11
|
CFLAGS := -O2 -Wall -Wextra -Wno-missing-field-initializers -std=c11 $(shell pkg-config --cflags sdl2 2>/dev/null)
|
||||||
LDFLAGS := -lglut -lGLU -lGL -lm
|
LDFLAGS := -lglut -lGLU -lGL -lm $(shell pkg-config --libs sdl2 2>/dev/null)
|
||||||
|
|
||||||
SRC := main.c
|
SRC := main.c
|
||||||
BIN := fps_demo
|
BIN := fps_demo
|
||||||
|
|||||||
@ -8,12 +8,12 @@ A tiny first-person demo using legacy OpenGL (compat) and FreeGLUT:
|
|||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
Requires development packages for OpenGL, GLU, and FreeGLUT.
|
Requires development packages for OpenGL, GLU, FreeGLUT, and SDL2 (for audio).
|
||||||
On Debian/Ubuntu:
|
On Debian/Ubuntu:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo apt-get update
|
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:
|
Then build and run:
|
||||||
@ -29,3 +29,4 @@ If your distro uses different package names, install the equivalents of:
|
|||||||
## Notes
|
## Notes
|
||||||
- This uses old-school fixed-function OpenGL for simplicity and broad compatibility.
|
- 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.
|
- 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).
|
||||||
|
|||||||
96
C/fps/main.c
96
C/fps/main.c
@ -12,6 +12,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
#ifndef M_PI
|
#ifndef M_PI
|
||||||
#define M_PI 3.14159265358979323846
|
#define M_PI 3.14159265358979323846
|
||||||
@ -84,6 +85,97 @@ static vec3 cam_right()
|
|||||||
return v3_norm(v3_cross(cam_front(), v3(0,1,0)));
|
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<frames; ++i) {
|
||||||
|
float t = (float)i / (float)frames;
|
||||||
|
// simple attack/decay envelope
|
||||||
|
float env = t < 0.1f ? (t/0.1f) : (1.0f - t);
|
||||||
|
if (env < 0.0f) env = 0.0f;
|
||||||
|
buf[i] = sinf(phase) * vol * env;
|
||||||
|
phase += dp;
|
||||||
|
}
|
||||||
|
audio_queue_samples(buf, frames);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void audio_play_sweep(float f0, float f1, 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;
|
||||||
|
for (int i=0; i<frames; ++i) {
|
||||||
|
float t = (float)i / (float)frames; // 0..1
|
||||||
|
float f = f0 + (f1 - f0) * t;
|
||||||
|
float dp = 2.0f * (float)M_PI * f / (float)sr;
|
||||||
|
float env = 1.0f - t; // fade out
|
||||||
|
buf[i] = sinf(phase) * vol * env;
|
||||||
|
phase += dp;
|
||||||
|
}
|
||||||
|
audio_queue_samples(buf, frames);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
static float frand(float a, float b) { return a + (b-a) * (rand()/(float)RAND_MAX); }
|
static float frand(float a, float b) { return a + (b-a) * (rand()/(float)RAND_MAX); }
|
||||||
|
|
||||||
static void clear_targets() { g_target_count = 0; }
|
static void clear_targets() { g_target_count = 0; }
|
||||||
@ -141,12 +233,14 @@ static void shoot()
|
|||||||
g_bullet_origin = g_cam_pos;
|
g_bullet_origin = g_cam_pos;
|
||||||
g_bullet_dir = dir;
|
g_bullet_dir = dir;
|
||||||
g_bullet_t = 0.08f; // show for ~80ms
|
g_bullet_t = 0.08f; // show for ~80ms
|
||||||
|
audio_play_tone(1600.0f, 0.05f, 0.25f); // shoot
|
||||||
|
|
||||||
if (best_i >= 0) {
|
if (best_i >= 0) {
|
||||||
// remove hit target (swap remove)
|
// remove hit target (swap remove)
|
||||||
g_targets[best_i] = g_targets[g_target_count-1];
|
g_targets[best_i] = g_targets[g_target_count-1];
|
||||||
g_target_count--;
|
g_target_count--;
|
||||||
g_score++;
|
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) {
|
if (dist2 <= reach*reach) {
|
||||||
g_state = GAME_OVER;
|
g_state = GAME_OVER;
|
||||||
glutSetCursor(GLUT_CURSOR_LEFT_ARROW);
|
glutSetCursor(GLUT_CURSOR_LEFT_ARROW);
|
||||||
|
audio_play_sweep(400.0f, 120.0f, 0.5f, 0.5f); // game over
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -433,6 +528,7 @@ int main(int argc, char** argv)
|
|||||||
glutCreateWindow("FPS Demo");
|
glutCreateWindow("FPS Demo");
|
||||||
|
|
||||||
init_gl();
|
init_gl();
|
||||||
|
audio_init();
|
||||||
|
|
||||||
glutDisplayFunc(display);
|
glutDisplayFunc(display);
|
||||||
glutIdleFunc(idle);
|
glutIdleFunc(idle);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user