ref: 9b9baca20eb6f5b86c460b5e7c0d3733fd5c6983
parent: ceb1c5733da57a554d3e06098eb0d26dc631f684
author: Jacob Moody <[email protected]>
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);
- }
}