76 lines
2.7 KiB
C
76 lines
2.7 KiB
C
#include "kknd.h"
|
|
|
|
/* =========================================================================
|
|
* audio.c - Procedural sound effects via SDL audio queue (no asset files).
|
|
* ========================================================================= */
|
|
|
|
static SDL_AudioDeviceID g_dev = 0;
|
|
static int g_audio_ok = 0;
|
|
|
|
int audio_init(void) {
|
|
SDL_AudioSpec want, have;
|
|
memset(&want, 0, sizeof want);
|
|
want.freq = 22050;
|
|
want.format = AUDIO_S16SYS;
|
|
want.channels = 1;
|
|
want.samples = 1024;
|
|
g_dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
|
|
if (g_dev == 0) { return 0; }
|
|
g_audio_ok = 1;
|
|
SDL_PauseAudioDevice(g_dev, 0);
|
|
return 1;
|
|
}
|
|
|
|
void audio_shutdown(void) {
|
|
if (g_dev) SDL_CloseAudioDevice(g_dev);
|
|
g_dev = 0; g_audio_ok = 0;
|
|
}
|
|
|
|
static void queue_tone(float freq, float dur, float vol, int kind) {
|
|
if (!g_audio_ok) return;
|
|
int n = (int)(22050 * dur);
|
|
int16_t *buf = (int16_t *)calloc((size_t)n, sizeof(int16_t));
|
|
for (int i = 0; i < n; i++) {
|
|
float t = (float)i / 22050.0f;
|
|
float env = (kind == 0) ? (1.0f - t / dur) : 1.0f;
|
|
float s = sinf(2*3.14159f*freq*t);
|
|
if (kind == 1) s = (sinf(2*3.14159f*freq*t) + 0.3f*sinf(2*3.14159f*freq*2*t));
|
|
if (kind == 2) s = (sinf(2*3.14159f*freq*t) * (1.0f - t/dur)) ;
|
|
buf[i] = (int16_t)(s * vol * 32767 * env);
|
|
}
|
|
SDL_QueueAudio(g_dev, buf, (Uint32)(n * sizeof(int16_t)));
|
|
free(buf);
|
|
}
|
|
|
|
void audio_sfx(int id) {
|
|
switch (id) {
|
|
case 0: queue_tone(440, 0.08f, 0.25f, 0); break; /* move */
|
|
case 1: queue_tone(220, 0.06f, 0.30f, 1); break; /* shoot */
|
|
case 2: queue_tone(90, 0.35f, 0.45f, 2); break; /* boom */
|
|
case 3: queue_tone(660, 0.10f, 0.30f, 0); break; /* build */
|
|
case 4: queue_tone(880, 0.05f, 0.25f, 0); break; /* select */
|
|
case 5: queue_tone(140, 0.12f, 0.35f, 1); break; /* error */
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
void audio_music_start(void) { /* procedural drone; intentionally silent by default */ }
|
|
void audio_music_stop(void) { /* no-op */ }
|
|
|
|
/* simple looping wasteland bassline (procedural, no asset files) */
|
|
static float g_music_t = 0;
|
|
static int g_music_step = 0;
|
|
static const float g_bass[8] = { 110.0f, 0, 146.8f, 0, 130.8f, 0, 98.0f, 0 };
|
|
static const float g_mel[8] = { 0, 329.6f, 0, 392.0f, 0, 293.7f, 0, 261.6f };
|
|
|
|
void audio_music_tick(float dt) {
|
|
if (!g_audio_ok) return;
|
|
g_music_t += dt;
|
|
const float step_dur = 0.40f;
|
|
if (g_music_t < step_dur) return;
|
|
g_music_t -= step_dur;
|
|
int s = g_music_step % 8;
|
|
if (g_bass[s] > 0) queue_tone(g_bass[s], step_dur * 0.95f, 0.10f, 2);
|
|
if (g_mel[s] > 0) queue_tone(g_mel[s], step_dur * 0.55f, 0.045f, 0);
|
|
g_music_step++;
|
|
}
|