4coder/platform_linux/linux_4ed_audio.cpp

133 lines
3.7 KiB
C++

#define ___fred_function function
#undef function
#include <alsa/asoundlib.h>
#include <poll.h>
#define function ___fred_function
internal void
linux_default_mix_sources(void *ctx, f32 *mix_buffer, u32 sample_count)
{
}
internal void
linux_default_mix_destination(i16 *dst, f32 *src, u32 sample_count)
{
u32 opl = sample_count*2;
for(u32 i = 0; i < sample_count; i += 1){
dst[i] = (i16)src[i];
}
}
internal struct alsa_funcs {
#define ALSA_FN(r,n,a) r (*n) a;
#include "alsa_funcs.txt"
#undef ALSA_FN
} snd_pcm;
internal void
linux_submit_audio(snd_pcm_t* pcm, i16* samples, u32 sample_count, f32* mix_buffer)
{
Audio_Mix_Sources_Function *audio_mix_src;
Audio_Mix_Destination_Function *audio_mix_dst;
pthread_mutex_lock(&linuxvars.audio_mutex);
audio_mix_src = linuxvars.audio_src_func;
audio_mix_dst = linuxvars.audio_dst_func;
void* audio_ctx = linuxvars.audio_ctx;
pthread_mutex_unlock(&linuxvars.audio_mutex);
if(!audio_mix_src) {
audio_mix_src = linux_default_mix_sources;
}
if(!audio_mix_dst) {
audio_mix_dst = linux_default_mix_destination;
}
audio_mix_src(audio_ctx, mix_buffer, sample_count);
audio_mix_dst(samples, mix_buffer, sample_count);
int err = snd_pcm.writei(pcm, samples, sample_count);
if(err < 0){
snd_pcm.recover(pcm, err, 1);
}
}
#define chk(x) ({\
int err = (x);\
if(err < 0){\
fprintf(stderr, "ALSA ERR: %s: [%d]\n", #x, err);\
}\
})
internal void
linux_audio_main(void* _unused)
{
const u32 SamplesPerSecond = 48000;
const u32 SamplesPerBuffer = 16*SamplesPerSecond/1000;
const u32 ChannelCount = 2;
const u32 BytesPerSample = 2; // S16LE
const u32 BufferSize = SamplesPerBuffer * BytesPerSample;
const u32 BufferCount = 3;
const u32 MixBufferSize = (SamplesPerBuffer * ChannelCount * sizeof(f32));
const u32 SampleBufferSize = (SamplesPerBuffer * ChannelCount * sizeof(i16));
void* lib = dlopen("libasound.so.2", RTLD_LOCAL | RTLD_LAZY);
if(!lib) {
fprintf(stderr, "failed to load libasound.so.2: %s", dlerror());\
return;
}
#define ALSA_FN(r,n,a)\
*((void**)&snd_pcm.n) = (void*)dlsym(lib, stringify(snd_pcm_##n));\
if(!snd_pcm.n){\
fprintf(stderr, "failed to load alsa func: %s", #n);\
return;\
}
#include "alsa_funcs.txt"
#undef ALSA_FN
snd_pcm_t* pcm;
chk( snd_pcm.open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0));
snd_pcm_hw_params_t* hw;
chk( snd_pcm.hw_params_malloc (&hw));
chk( snd_pcm.hw_params_any (pcm, hw));
chk( snd_pcm.hw_params_set_access (pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED));
chk( snd_pcm.hw_params_set_format (pcm, hw, SND_PCM_FORMAT_S16_LE));
chk( snd_pcm.hw_params_set_channels (pcm, hw, ChannelCount));
chk( snd_pcm.hw_params_set_rate (pcm, hw, SamplesPerSecond, 0));
chk( snd_pcm.hw_params_set_buffer_size (pcm, hw, BufferSize * BufferCount));
chk( snd_pcm.hw_params (pcm, hw));
snd_pcm.hw_params_free (hw);
int fd_count = snd_pcm.poll_descriptors_count(pcm);
struct pollfd* fds = (struct pollfd*)calloc(fd_count, sizeof(struct pollfd));
snd_pcm.poll_descriptors(pcm, fds, fd_count);
for(;;) {
int n = poll(fds, fd_count, -1);
if(n == -1) {
perror("poll");
continue;
}
f32* MixBuffer = (f32*)calloc(1, MixBufferSize);
i16* SampleBuffer = (i16*)calloc(1, SampleBufferSize);
if(!MixBuffer || !SampleBuffer) {
perror("calloc");
continue;
}
linux_submit_audio(pcm, SampleBuffer, SamplesPerBuffer, MixBuffer);
free(MixBuffer);
free(SampleBuffer);
}
}
#undef chk