shithub: npe

ref: 80d7f985cb1d0b8aa8702a95edfa71dd9ec10a37
dir: /libnpe_sdl2/mixer.c/

View raw version
#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 audioexec(void *);
void audioforker(void *);
void audioproc(void *);

static int musicvol = 128;
static int musicpaused = 0;

/* FIXME proper chains per channel */
Mix_EffectFunc_t effunc = nil;

int
Mix_OpenAudio(int freq, Uint16 format, int channels, int chunk)
{
	USED(freq);
	USED(format);
	USED(channels);
	USED(chunk);

	return 0;
}

char*
Mix_GetError(void)
{
	return "";
}

int
Mix_RegisterEffect(int chan, Mix_EffectFunc_t f, Mix_EffectDone_t d, void *arg)
{
	USED(chan);
	USED(f);
	USED(d);
	USED(arg);
	effunc = f;
	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)
{
	audiofd = open("/dev/audio", OWRITE);
	if(audiofd < 0)
		return -1;

	audiopid = proccreate(audioproc, nil, 4096);
	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)
{
	int x, y;
	if(forkerpid < 0)
		return 0;

	postnote(PNGROUP, forkerpid, "halt");
	x = musicpipe[0];
	y = musicpipe[1];
	musicpipe[0] = -1;
	musicpipe[1] = -1;
	close(x); close(y);
	forkerpid = -1;
	return 0;
}

int
Mix_PlayMusic(Mix_Music *music, int loops)
{
	music->loops = loops;
	pipe(musicpipe);
	forkerpid = procrfork(audioforker, music, 4096, RFNOTEG);
	return 0;
}

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/duke3d.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);

	if(freesrc)
		SDL_RWclose(src);
	return m;
}

void
audioexec(void *arg)
{
	Mix_Music *m;
	int i;

	m = arg;
	seek(m->fd, 0, 0);
	dup(musicpipe[0], 1);
	dup(m->fd, 0);
	close(musicpipe[1]);
	procexecl(nil, "/bin/games/midi", "midi", "-c", nil);
}

void
audioforker(void *arg)
{
	Mix_Music *m;
	Waitmsg *wm;
	Channel *c;

	m = arg;
	c = threadwaitchan();
	while(m->loops-- != 0){
		procrfork(audioexec, m, 4096, RFFDG);
		wm = recvp(c);
		if(wm->msg != nil){
			fprint(2, "err %s\n", wm->msg);
			free(wm);
			break;
		}
		free(wm);
	}
}

void
audioproc(void *)
{
	static uchar buf[1024];
	static uchar sounds[1024];
	s16int *mu;
	s16int *so;
	int i, n;
	long v;

	mu = (s16int*)buf;
	so = (s16int*)sounds;
	for(;;){
		memset(buf, 0, sizeof buf);
		if(musicpipe[1] > 0 && !musicpaused){
			n = read(musicpipe[1], buf, sizeof buf);
			if(n < 0)
				continue;

			for(i = 0; i < n/sizeof(*mu); i++)
				mu[i] = ((long)mu[i] * musicvol)/128;	
		} else {
			n = 0;	
		}


		if(effunc != nil){
			effunc(0, sounds, sizeof sounds, nil);
			for(i = 0; i < sizeof sounds/sizeof(*so); i++){
				v = mu[i] + so[i];
				if(v > 0x7fff)
					v = 0x7fff;
				else if(v < -0x8000)
					v = -0x8000;
				mu[i] = v;
			}
			n = sizeof sounds;
		}

		write(audiofd, buf, n);
	}
}