ref: 481982eca1360fc710e240f6b7757572a1cf8c74
parent: aeecf799ccb7461d436e3c3a07357ca0fff73180
author: Jacob Moody <moody@posixcafe.org>
date: Thu Feb 9 22:01:17 EST 2023
jank mixer
--- a/include/npe/SDL2/SDL_mixer.h
+++ b/include/npe/SDL2/SDL_mixer.h
@@ -13,6 +13,9 @@
typedef struct Mix_Music {
int type;
+ int loops;
+ int fd;
+ char *loc;
} Mix_Music;
typedef void (*Mix_EffectFunc_t)(int chan, void *stream, int len, void *udata);
--- a/libnpe_sdl2/mixer.c
+++ b/libnpe_sdl2/mixer.c
@@ -2,6 +2,22 @@
#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)
{
@@ -10,7 +26,7 @@
USED(channels);
USED(chunk);
- return 0; //lies
+ return 0;
}
char*
@@ -26,6 +42,7 @@
USED(f);
USED(d);
USED(arg);
+ effunc = f;
return 1;
}
@@ -62,20 +79,30 @@
void
Mix_CloseAudio(void)
{
-
+ if(audiopid > 0)
+ postnote(PNPROC, audiopid, "quit");
+ audiopid = -1;
}
int
Mix_Init(int flags)
{
- USED(flags);
- return 0;
+ audiofd = open("/dev/audio", OWRITE);
+ if(audiofd < 0)
+ return -1;
+
+ audiopid = proccreate(audioproc, nil, 4096);
+ return flags;
}
int
Mix_VolumeMusic(int vol)
{
- USED(vol);
+ if(vol < 0)
+ vol = 0;
+ else if(vol > 128)
+ vol = 128;
+ musicvol = vol;
return 0;
}
@@ -82,28 +109,40 @@
int
Mix_PlayingMusic(void)
{
- return 0;
+ return forkerpid > 0 && !musicpaused;
}
int
Mix_PausedMusic(void)
{
- return 0;
+ 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;
}
@@ -110,8 +149,9 @@
int
Mix_PlayMusic(Mix_Music *music, int loops)
{
- USED(music);
- USED(loops);
+ music->loops = loops;
+ pipe(musicpipe);
+ forkerpid = procrfork(audioforker, music, 4096, RFNOTEG);
return 0;
}
@@ -118,7 +158,95 @@
Mix_Music*
Mix_LoadMUS_RW(SDL_RWops *src, int freesrc)
{
- USED(src);
- USED(freesrc);
- return nil;
+ 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);
+ }
}