shithub: npe

Download patch

ref: 9b9baca20eb6f5b86c460b5e7c0d3733fd5c6983
parent: ceb1c5733da57a554d3e06098eb0d26dc631f684
author: Jacob Moody <moody@posixcafe.org>
date: Sun Feb 12 02:07:20 EST 2023

refactor mixer

--- a/include/npe/SDL2/SDL_mixer.h
+++ b/include/npe/SDL2/SDL_mixer.h
@@ -40,6 +40,7 @@
 int Mix_HaltMusic(void);
 int Mix_PlayMusic(Mix_Music *music, int loops);
 Mix_Music* Mix_LoadMUS_RW(SDL_RWops *src, int freesrc);
+Mix_Music* Mix_LoadMUS(char *filename);
 
 enum {
 	MIX_INIT_MID = 1,
--- a/libnpe_sdl2/mixer.c
+++ b/libnpe_sdl2/mixer.c
@@ -18,14 +18,42 @@
 /* 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 channels, int chunk)
+Mix_OpenAudio(int freq, Uint16 format, int nch, int chunk)
 {
-	USED(freq);
-	USED(format);
-	USED(channels);
-	USED(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;
 }
 
@@ -35,14 +63,33 @@
 	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)
 {
-	USED(chan);
-	USED(f);
-	USED(d);
-	USED(arg);
-	effunc = f;
+	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);
+	SDL_PauseAudioDevice(2, 0);
+	
 	return 1;
 }
 
@@ -87,11 +134,15 @@
 int
 Mix_Init(int flags)
 {
-	audiofd = open("/dev/audio", OWRITE);
-	if(audiofd < 0)
-		return -1;
-
-	audiopid = proccreate(audioproc, nil, 4096);
+	if(doneinit)
+		return flags;
+	doneinit = 1;
+	memset(channels, 0, sizeof channels);
+	rfork(RFNAMEG);
+	if(rfork(RFPROC|RFFDG) == 0){
+		execl("/bin/audio/mixfs", "mixfs", nil);
+		sysfatal("exec: %r\n");
+	}
 	return flags;
 }
 
@@ -132,16 +183,10 @@
 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;
 }
@@ -149,13 +194,50 @@
 int
 Mix_PlayMusic(Mix_Music *music, int loops)
 {
-	music->loops = loops;
-	pipe(musicpipe);
-	forkerpid = procrfork(audioforker, music, 4096, RFNOTEG);
-	return 0;
+	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:
+			execl("/bin/games/midi", "midi", 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;
@@ -163,90 +245,13 @@
 	int n;
 
 	m = calloc(1, sizeof(*m));
-	m->loc = smprint("/tmp/duke3d.mus.%d", getpid());
+	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
-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);
-	}
 }