shithub: hexen

Download patch

ref: d88f201b76b8f1021e3b20fb487fcc3c49e6503b
parent: dc803493f4a4f35e7713a9ee52b635558add5b9d
author: Jacob Moody <moody@posixcafe.org>
date: Sun Jan 22 22:51:42 EST 2023

mix in music

--- a/i_sound.c
+++ b/i_sound.c
@@ -81,6 +81,10 @@
 
 static QLock audiolk;
 
+boolean mus_paused = false;
+
+static int mpfd[2] = {-1, -1};
+
 static void audioproc(void)
 {
 	Channel* chan;
@@ -97,6 +101,11 @@
 	cend = channel + CHAN_COUNT;
 
 	for(;;){
+		memset(buf, 0, sizeof buf);
+		if(mpfd[0]>=0 && !mus_paused && readn(mpfd[0], buf, sizeof buf) < 0){
+			fprint(2, "I_UpdateSound: disabling music: %r\n");
+			I_ShutdownMusic();
+		}
 		begin = (SAMPLE_TYPE *) buf;
 		while (begin < end){
 			// Mix all the channels together.
@@ -137,8 +146,8 @@
 					dr = 0x7fff;
 				else if (dr < -0x8000)
 					dr = -0x8000;
-				*begin++ = dl;
-				*begin++ = dr;
+				*begin++ += dl;
+				*begin++ += dr;
 			}
 		}
 		write(audiofd, buf, BUF_LEN);
@@ -324,6 +333,7 @@
 		postnote(PNPROC, audiopid, "shutdown");
 		audiopid = -1;
 	}
+	I_ShutdownMusic();
 }
 
 void I_SetChannels(int channels)
@@ -368,12 +378,54 @@
  *	SONG API
  */
 
-int I_RegisterSong(void *data)
+static int didgen = 0;
+
+static void genmidi(void)
 {
-	USED(data);
-	return 0;
+	int fd, n, sz;
+	char name[64];
+	uchar *gm;
+
+	n = W_GetNumForName("GENMIDI");
+	sz = W_LumpLength(n);
+	gm = (uchar *)W_CacheLumpNum(n, PU_STATIC);
+	snprint(name, sizeof(name), "/tmp/genmidi.%d", getpid());
+	if((fd = create(name, ORDWR|ORCLOSE, 0666)) < 0)
+		sysfatal("create: %r");
+	if(write(fd, gm, sz) != sz)
+			sysfatal("write: %r");
+	Z_Free(gm);
 }
 
+void I_ShutdownMusic(void)
+{
+	if(mpfd[0] >= 0){
+		close(mpfd[0]);
+		mpfd[0] = -1;
+		waitpid();
+	}
+}
+
+
+/* In theory this allows register step allows 
+ * the use of external files in place of internal ones. */
+static void *currentsong = nil;
+static int currentsize = 0;
+
+int I_RegisterSong(void *data, int siz)
+{
+	if(!didgen){
+		genmidi();
+		didgen++;
+	}
+	if(currentsong != nil)
+		return 0;
+
+	currentsong = data;
+	currentsize = siz;
+	return 1;
+}
+
 int I_RegisterExternalSong(const char *nm)
 {
 	USED(nm);
@@ -383,16 +435,21 @@
 void I_UnRegisterSong(int handle)
 {
 	USED(handle);
+	currentsong = nil;
 }
 
 void I_PauseSong(int handle)
 {
-	USED(handle);
+	if(handle <= 0)
+		return;
+	mus_paused = true;
 }
 
 void I_ResumeSong(int handle)
 {
-	USED(handle);
+	if(handle <= 0)
+		return;
+	mus_paused = false;
 }
 
 void I_SetMusicVolume(int volume)
@@ -409,11 +466,48 @@
 // Stops a song.  MUST be called before I_UnregisterSong().
 void I_StopSong(int handle)
 {
-	USED(handle);
+	if(handle <= 0)
+		return;
+	I_ShutdownMusic();
 }
 
-void I_PlaySong(int handle, boolean looping)
+void I_PlaySong(int handle, boolean loop)
 {
-	USED(handle); USED(looping);
+	char name[64];
+	int n;
+
+	if(M_CheckParm("-nomusic") || audiofd < 0 || handle <= 0)
+		return;
+
+	I_ShutdownMusic();
+	if(pipe(mpfd) < 0)
+		return;
+	switch(rfork(RFPROC|RFFDG|RFNAMEG)){
+	case -1:
+		fprint(2, "I_PlaySong: %r\n");
+		break;
+	case 0:
+		dup(mpfd[1], 1);
+		for(n=3; n<20; n++) close(n);
+		close(0);
+		snprint(name, sizeof(name), "/tmp/hexen.%d", getpid());
+		if(create(name, ORDWR|ORCLOSE, 0666) != 0)
+			sysfatal("create: %r");
+		if(write(0, currentsong, currentsize) != currentsize)
+			sysfatal("write: %r");
+		if(seek(0, 0, 0) != 0)
+			sysfatal("seek: %r");
+		if(bind("/fd/1", "/dev/audio", MREPL) == -1)
+			sysfatal("bind: %r");
+		while(loop && fork() > 0){
+			if(waitpid() < 0 || write(1, "", 0) < 0)
+				exits(nil);
+		}
+		execl("/bin/dmus", "dmus", name, nil);
+		execl("/bin/play", "play", name, nil);
+		sysfatal("execl: %r");
+	default:
+		close(mpfd[1]);
+	}
 }
 
--- a/i_sound.h
+++ b/i_sound.h
@@ -38,7 +38,7 @@
 // ... shut down and relase at program termination.
 void I_ShutdownSound(void);
 
-int	I_RegisterSong(void *data);
+int	I_RegisterSong(void *data, int siz);
 void	I_UnRegisterSong(int handle);
 int	I_RegisterExternalSong(char *name);
 
--- a/s_sound.c
+++ b/s_sound.c
@@ -478,7 +478,7 @@
 void S_StartSong(int song, boolean loop)
 {
 	const char *songLump;
-	int track;
+	int track, length;
 
 	if (i_CDMusic && cdaudio)
 	{ // Play a CD track, instead
@@ -553,17 +553,18 @@
 		{
 			char name[MAX_OSPATH];
 			snprintf(name, sizeof(name), "%s%s.lmp", ArchivePath, songLump);
-			M_ReadFile(name, &Mus_SndPtr);
+			length = M_ReadFile(name, &Mus_SndPtr);
 		}
 		else
 		{
 			Mus_LumpNum = W_GetNumForName(songLump);
+			length = W_LumpLength(Mus_LumpNum);
 			Mus_SndPtr = W_CacheLumpNum(Mus_LumpNum, PU_MUSIC);
 		}
 #ifdef __WATCOMC__
 		_dpmi_lockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
 #endif
-		RegisteredSong = I_RegisterSong(Mus_SndPtr);
+		RegisteredSong = I_RegisterSong(Mus_SndPtr, length);
 		I_PlaySong(RegisteredSong, loop);	// 'true' denotes endless looping.
 		Mus_Song = song;
 	}
@@ -578,6 +579,7 @@
 void S_StartSongName(const char *songLump, boolean loop)
 {
 	int cdTrack;
+	int length;
 
 	if (!songLump)
 	{
@@ -668,17 +670,18 @@
 		{
 			char name[MAX_OSPATH];
 			snprintf(name, sizeof(name), "%s%s.lmp", ArchivePath, songLump);
-			M_ReadFile(name, &Mus_SndPtr);
+			length = M_ReadFile(name, &Mus_SndPtr);
 		}
 		else
 		{
 			Mus_LumpNum = W_GetNumForName(songLump);
+			length = W_LumpLength(Mus_LumpNum);
 			Mus_SndPtr = W_CacheLumpNum(Mus_LumpNum, PU_MUSIC);
 		}
 #ifdef __WATCOMC__
 		_dpmi_lockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
 #endif
-		RegisteredSong = I_RegisterSong(Mus_SndPtr);
+		RegisteredSong = I_RegisterSong(Mus_SndPtr, length);
 		I_PlaySong(RegisteredSong, loop);	// 'true' denotes endless looping.
 		Mus_Song = -1;
 	}