trueno/src/audio/mixer.jai
2026-01-28 23:29:30 +02:00

88 lines
2.1 KiB
Plaintext

#if OS != .WASM {
Thread :: #import "Thread";
}
Mixer_Bus :: enum {
MUSIC;
SOUND_EFFECT;
DIALOGUE;
}
Play_Mode :: enum {
ONESHOT;
REPEAT;
}
Mixer_Play_Task :: struct {
audio : *Audio_Data;
bus : Mixer_Bus;
mode : Play_Mode;
curSample : s64;
startTime : float64;
delay : float64;
silenceBeforeRepeat : float64;
}
Mixer_Config :: struct {
masterVolume : float = 0.5; @Slider,0,1,0.1
dialogueVolume : float = 0.5; @Slider,0,1,0.1
soundEffectVolume : float = 0.5; @Slider,0,1,0.1
}
Mixer :: struct {
#if OS != .WASM {
// If we are on WASM, the Thread module mutex does not work.
// Fortunately we don't need a mutex for this, since sokol does
// not do multithreading for audio on WASM.
//
// Let's just have the mutex as a part of the struct on all platforms
// except WASM. It would probably be a good idea to have a mutex wrapper
// thing that would use the Thread module Mutex or a mutex that works with
// WASM. :NoMutexForWasm
mutex : Thread.Mutex;
}
config : Mixer_Config;
tasks : [..]Mixer_Play_Task;
}
// Removes tasks from the mixer's task list that
// no longer have a reason to be on the task list.
// Eg. a sound that is .ONESHOT but has already been played.
mixer_clean_tasks :: (mixer: *Mixer) {
mixer_lock(mixer);
defer mixer_unlock(mixer);
}
mixer_add_task :: (mixer: *Mixer, task: Mixer_Play_Task) {
mixer_lock(mixer);
defer mixer_unlock(mixer);
}
mixer_get_samples :: (mixer: *Mixer, samples: *float, sampleCount: s32, channelCount: s32) {
mixer_lock(mixer);
defer mixer_unlock(mixer);
}
mixer_lock :: (mixer: *Mixer) {
#if OS != .WASM {
Thread.lock(*mixer.mutex);
} else {
return; // On WASM this is a no-op. See :NoMutexForWasm
}
}
mixer_unlock :: (mixer: *Mixer) {
#if OS != .WASM {
Thread.unlock(*mixer.mutex);
} else {
return; // On WASM this is a no-op. See :NoMutexForWasm
}
}