153 lines
3.4 KiB
C
153 lines
3.4 KiB
C
#include "audio.h"
|
|
#include "raylib.h"
|
|
#include "common.h"
|
|
#include <math.h>
|
|
#include <stddef.h>
|
|
|
|
#ifndef M_PI
|
|
#define M_PI 3.14159265358979323846 // xd
|
|
#endif
|
|
|
|
#define SAMPLE_RATE 44100
|
|
#define DURATION 0.1
|
|
|
|
// Generate a simple sine wave tone
|
|
static void play_tone(float frequency, float duration, float volume) {
|
|
int sample_count = (int)(SAMPLE_RATE * duration);
|
|
|
|
if (sample_count > SAMPLE_RATE)
|
|
sample_count = SAMPLE_RATE;
|
|
if (sample_count <= 0)
|
|
return;
|
|
|
|
// Allocate samples dynamically to avoid shared static buffer corruption
|
|
float *samples = (float *)MemAlloc(sample_count * sizeof(float));
|
|
if (samples == NULL)
|
|
return;
|
|
|
|
// Generate sine wave
|
|
for (int i = 0; i < sample_count; i++) {
|
|
float t = (float)i / SAMPLE_RATE;
|
|
samples[i] = sinf(2.0f * M_PI * frequency * t) * volume;
|
|
|
|
// Apply simple envelope (fade in/out)
|
|
float envelope = 1.0f;
|
|
int fade_samples = SAMPLE_RATE / 20; // 50ms fade
|
|
if (i < fade_samples) {
|
|
envelope = (float)i / fade_samples;
|
|
} else if (i > sample_count - fade_samples) {
|
|
envelope = (float)(sample_count - i) / fade_samples;
|
|
}
|
|
samples[i] *= envelope;
|
|
}
|
|
|
|
// Create wave from samples
|
|
Wave wave = {.frameCount = (unsigned int)sample_count,
|
|
.sampleRate = SAMPLE_RATE,
|
|
.sampleSize = 32,
|
|
.channels = 1,
|
|
.data = samples};
|
|
|
|
Sound sound = LoadSoundFromWave(wave);
|
|
PlaySound(sound);
|
|
UnloadSound(sound);
|
|
|
|
// Free the dynamically allocated buffer
|
|
MemFree(samples);
|
|
}
|
|
|
|
void audio_init(void) {
|
|
// Initialize audio device
|
|
InitAudioDevice();
|
|
}
|
|
|
|
void audio_close(void) {
|
|
// Close audio device
|
|
CloseAudioDevice();
|
|
}
|
|
|
|
void audio_play_move(void) {
|
|
// Low blip for movement
|
|
play_tone(200.0f, 0.05f, 0.3f);
|
|
}
|
|
|
|
void audio_play_attack(GameState *gs) {
|
|
// Mid-range hit sound
|
|
// play_tone(400.0f, 0.1f, 0.5f);
|
|
int choice = GetRandomValue(1, 3);
|
|
switch (choice) {
|
|
case 1:
|
|
PlaySound(gs->sounds.attack1);
|
|
break;
|
|
case 2:
|
|
PlaySound(gs->sounds.attack2);
|
|
break;
|
|
case 3:
|
|
PlaySound(gs->sounds.attack3);
|
|
break;
|
|
default:
|
|
PlaySound(gs->sounds.attack1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void audio_play_item_pickup(GameState *gs) {
|
|
// High-pitched pickup sound
|
|
PlaySound(gs->sounds.pickup);
|
|
}
|
|
|
|
void audio_play_enemy_death(GameState *gs) {
|
|
// Descending death sound
|
|
play_tone(300.0f, 0.1f, 0.5f);
|
|
play_tone(150.0f, 0.15f, 0.4f);
|
|
}
|
|
|
|
void audio_play_player_damage(GameState *gs) {
|
|
// Harsh damage sound
|
|
play_tone(150.0f, 0.1f, 0.6f);
|
|
play_tone(100.0f, 0.1f, 0.4f);
|
|
}
|
|
|
|
void audio_play_stairs(GameState *gs) {
|
|
// Ascending stairs sound
|
|
PlaySound(gs->sounds.staircase);
|
|
}
|
|
|
|
void audio_play_dodge(GameState *gs) {
|
|
// High-pitched whoosh
|
|
// play_tone(900.0f, 0.08f, 0.3f);
|
|
int choice = GetRandomValue(1, 3);
|
|
switch (choice) {
|
|
case 1:
|
|
PlaySound(gs->sounds.dodge1);
|
|
break;
|
|
case 2:
|
|
PlaySound(gs->sounds.dodge2);
|
|
break;
|
|
case 3:
|
|
PlaySound(gs->sounds.dodge3);
|
|
break;
|
|
default:
|
|
PlaySound(gs->sounds.dodge1);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void audio_play_block(GameState *gs) {
|
|
// Low-then-mid metallic clang
|
|
play_tone(250.0f, 0.06f, 0.5f);
|
|
play_tone(350.0f, 0.04f, 0.3f);
|
|
}
|
|
|
|
void audio_play_crit(GameState *gs) {
|
|
// Sharp crack with high-pitched follow
|
|
audio_play_attack(gs);
|
|
PlaySound(gs->sounds.crit);
|
|
}
|
|
|
|
void audio_play_proc(void) {
|
|
// Ascending two-tone proc chime
|
|
play_tone(500.0f, 0.08f, 0.4f);
|
|
play_tone(700.0f, 0.1f, 0.35f);
|
|
}
|