133 lines
3.7 KiB
C++
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
|