ref: 720ba9765a63caefebafc4d2923dd10febfe99e9
dir: /libnpe_sdl2/mixer.c/
#include "_sdl.h"
#include <SDL2/SDL_mixer.h>
int audiofd = -1;
int musicpipe[2] = {-1, -1};
static int forkerpid = -1;
static int audiopid = -1;
void musicproc(void *);
static int musicvol = 128;
static int musicpaused = 0;
/* FIXME proper chains per channel */
Mix_EffectFunc_t effunc = nil;
static int doneinit = 0;
static int devopen = 0;
enum { Maxchan = 16 };
SDL_AudioSpec channels[Maxchan];
int nchannels = 0;
int
Mix_OpenAudio(int freq, Uint16 format, int nch, int chunk)
{
SDL_AudioSpec *as;
int sz;
if(devopen)
return 0;
switch(format){
case 1:
case 2:
sz = 1;
break;
case 3:
case 4:
sz = 2;
break;
default:
werrstr("unsupported format");
return -1;
}
as = &channels[nchannels++];
assert(nchannels < Maxchan);
as->freq = freq;
as->format = format;
as->channels = nch;
as->samples = chunk / sz;
return 0;
}
char*
Mix_GetError(void)
{
return "";
}
static void
translate(void *arg, Uint8 *buf, int len)
{
Mix_EffectFunc_t f;
f = (Mix_EffectFunc_t)arg;
f(0, buf, len, nil);
}
int
Mix_RegisterEffect(int chan, Mix_EffectFunc_t f, Mix_EffectDone_t d, void *arg)
{
SDL_AudioSpec *as;
int n;
USED(arg); USED(d);
as = channels + chan;
as->userdata = f;
as->callback = translate;
if(devopen){
werrstr("device already open");
return -1;
}
n = SDL_OpenAudioDevice(nil, 0, as, nil, 0);
assert(n >= 0);
SDL_PauseAudioDevice(n, 0);
return 1;
}
Mix_Chunk*
Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len)
{
USED(mem);
USED(len);
return nil;
}
int
Mix_PlayChannel(int chan, Mix_Chunk *chunk, int loops)
{
USED(chan);
USED(chunk);
USED(loops);
return -1;
}
int
Mix_HaltChannel(int channel)
{
USED(channel);
return 0;
}
void
Mix_FreeChunk(Mix_Chunk *c)
{
USED(c);
}
void
Mix_CloseAudio(void)
{
if(audiopid > 0)
postnote(PNPROC, audiopid, "quit");
audiopid = -1;
}
int
Mix_Init(int flags)
{
if(doneinit)
return flags;
doneinit = 1;
memset(channels, 0, sizeof channels);
rfork(RFNAMEG);
if(fork() == 0){
execl("/bin/audio/mixfs", "mixfs", nil);
sysfatal("exec: %r\n");
}
waitpid();
pipe(musicpipe);
if(fork() == 0){
musicproc(nil);
sysfatal("exec musicproc: %r");
}
return flags;
}
int
Mix_VolumeMusic(int vol)
{
if(vol < 0)
vol = 0;
else if(vol > 128)
vol = 128;
musicvol = vol;
return 0;
}
int
Mix_PlayingMusic(void)
{
return forkerpid > 0 && !musicpaused;
}
int
Mix_PausedMusic(void)
{
return musicpaused;
}
void
Mix_ResumeMusic(void)
{
musicpaused = 0;
}
void
Mix_PauseMusic(void)
{
musicpaused = 1;
}
int
Mix_HaltMusic(void)
{
if(forkerpid < 0)
return 0;
postnote(PNGROUP, forkerpid, "halt");
forkerpid = -1;
return 0;
}
int
Mix_PlayMusic(Mix_Music *music, int loops)
{
Waitmsg *wm;
int n;
if(forkerpid > 0)
Mix_HaltMusic();
if((forkerpid = rfork(RFPROC|RFNOTEG)) != 0)
return 0;
n = loops;
while(loops == -1 || n-- > 0){
switch(rfork(RFPROC|RFFDG)){
case 0:
dup(musicpipe[1], 1);
close(musicpipe[1]);
close(musicpipe[0]);
execl("/bin/games/midi", "midi", "-c", music->loc, nil);
sysfatal("exec: %r");
break;
default:
wm = wait();
if(wm->msg != nil && wm->msg[0] != '\0'){
fprint(2, "playmusic: %s\n", wm->msg);
threadexits(nil);
}
free(wm);
break;
}
}
threadexits(nil);
return -1;
}
Mix_Music*
Mix_LoadMUS(char *filename)
{
Mix_Music *m;
m = calloc(1, sizeof(*m));
m->loc = strdup(filename);
m->fd = open(filename, OREAD);
if(m->fd < 0)
sysfatal("LoadMUS: %r");
return m;
}
Mix_Music*
Mix_LoadMUS_RW(SDL_RWops *src, int freesrc)
{
Mix_Music *m;
char buf[1024];
int n;
m = calloc(1, sizeof(*m));
m->loc = smprint("/tmp/npesdl.mus.%d", getpid());
m->fd = create(m->loc, ORDWR|ORCLOSE, 0666);
while((n = SDL_RWread(src, buf, 1, sizeof buf)) > 0)
write(m->fd, buf, n);
seek(m->fd, 0, 0);
if(freesrc)
SDL_RWclose(src);
return m;
}
void
musicproc(void *)
{
int fd;
static char buf[8192];
int n;
fd = open("/dev/audio", OWRITE);
if(fd < 0)
sysfatal("musicproc: %r");
close(musicpipe[1]);
threadsetname("musicproc");
for(;;){
n = read(musicpipe[0], buf, sizeof buf);
if(n < 0)
threadexits(nil);
write(fd, buf, n);
}
}