$NetBSD: patch-ab,v 1.2 2000/12/18 00:03:38 wiz Exp $

--- sys/NetBSD/audio.c.orig	Sun May 23 10:29:13 1999
+++ sys/NetBSD/audio.c	Sun May 23 10:55:39 1999
@@ -0,0 +1,298 @@
+/*
+ *  NetBSD $B%5%&%s%I=hM}(B
+ */
+
+/*
+ *  Copyright (c) 1994 Kazuhiko Ishii.
+ *  Copyright (c) 1995 Masanobu Saitoh.
+ *
+ *  $BK\%=%U%H%&%'%"$N%=!<%9$d%P%$%J%j$r:FG[I[$9$k>l9g$O!"<!$N>r7o$r=e<i$7$F(B
+ *  $B2<$5$$!#(B
+ *
+ *  1. $BK\%=%U%H%&%'%"$rF~<j$7$?J}$K$O!"(BX11$BHG(B Emi Clock $B$N;HMQ8"$H!"Bh;0<T(B
+ *     $B$X$N:FG[I[8"$,G'$a$i$l$^$9!#$?$@$7!":FG[I[$K4X$7$F$O!"F~<j;~$N%*%j(B
+ *     $B%8%J%k$N$^$^2~JQ$;$:$K9T$&$3$H$,>r7o$G$9!#(B
+ *  2. $BK\%=%U%H%&%'%"$N0lIt$^$?$OA4It$rCx:n8"<T$KL5CG$G2~JQ$7$FG[I[$9$k$3(B
+ *     $B$H$O$G$-$^$;$s!#(B
+ *  3. $BK\%=%U%H%&%'%"$N0lIt$^$?$OA4It$rCx:n8"<T$KL5CG$GFs<!MxMQ$9$k$3$H$O(B
+ *     $B$G$-$^$;$s!#(B
+ *  4. $BK\%=%U%H%&%'%"$r%7%9%F%`$K%P%s%I%k$7$?$j!"%7%9%F%`$NDI2C%Q%C%1!<%8(B
+ *     $B$H$7$FBh;0<T$K:FG[I[$7$?$j$9$k>l9g$O!";vA0$KCx:n8"<T$K5v2D$,I,MW$G(B
+ *     $B$9!#(B
+ *  5. $BK\%=%U%H%&%'%"$r>&MQ$K;HMQ$9$k>l9g(B($B6bA,E*Mx1W$rF@$k>l9g(B)$B$O!";vA0$K(B
+ *     $BCx:n8"<T$K5v2D$,I,MW$G$9!#$3$N>l9g!"4pK\E*$KM-=~$H$J$j$^$9!#(B
+ *  6. $BK\%=%U%H%&%'%"$rMxMQ$9$k$3$H$K$h$C$FH/@8$7$?$$$+$J$kB;32$b!"Cx:n8"(B
+ *     $B<T$OIi$o$J$$$b$N$H$7$^$9!#$3$l$K9g0U$G$-$J$$>l9g$O!";HMQ8"$,$J$$$b(B
+ *     $B$N$H$7$^$9!#(B
+ *  7. $B!H(BEmi Clock$B!I$N>&I8$*$h$SK\%=%U%H%&%'%"$N2hA|$d%G%6%$%s$K4X$9$kCx:n(B
+ *     $B8"$O!"(BMotosoft $B$3$H!HK\(B $B=SLi!I;a$,M-$7$^$9!#(B
+ *  8. $B!H(BEmi Clock$B!I$N>&I8$*$h$S2hA|$d%G%6%$%s$O!"(BX11$BHG(B Emi Clock $B3+H/$N$?(B
+ *     $B$a!"(BMotosoft $B$h$j!H8E>l(B $B@59T!I$X8D?ME*$K%i%$%;%s%96!M?$5$l$F$^$9!#(B
+ *     $BBh;0<T$XFs<!%i%$%;%s%96!M?$9$k$3$H$OG'$a$i$l$F$*$j$^$;$s!#(B
+ *  9. Motosoft $B$H8E>l$KL5CG$G!"K\%=%U%H%&%'%"$N2hA|%G!<%?$rFs<!MxMQ$9$k$3(B
+ *     $B$H$r6X;_$7$^$9!#(B
+ * 10. $B$3$3$K5-=R$7$?0J30$N8"Mx$K$D$$$F$O!"F|K\9q$NCx:n8"K!$K$h$k$b$N$H$7(B
+ *     $B$^$9!#(B
+ */
+
+
+/* $BDj?t(B */
+#define	HAS_SOUND_CODE		/* $B%5%&%s%I4X78$N%3!<%I$OM-8z!*(B */
+
+/* RCS ID */
+rcsId(audioId, "Id: audio.c,v 1.5 1994/05/31 06:28:21 masa-k Rel ")
+
+static int	S_AuFileHeader();
+static void	S_PlayInterval();
+
+static int		AudioDevice;
+static audio_info_t	AudioSaveConfig;
+static int		SoundLeft;
+static int		SoundPlayed;
+static int		SoundTimeBytes;
+static char		*SoundBufPtr;
+static char		*SoundTmpBuffer = NULL;
+static struct timeval	SoundStart;
+
+/*
+ *  $B%5%&%s%I4D6-$N=i4|2=(B
+ */
+static void
+S_SoundEnvInit()
+{
+    /* $B2?$b$7$J$$(B */
+}
+
+
+/*
+ *  $B%5%&%s%I%G%P%$%9$NB8:_H=Dj(B
+ */
+static Boolean
+S_IsSoundAvailable()
+{
+	struct stat	st;
+
+	/* $B%*!<%G%#%*#I!?#F$N%A%'%C%/(B */
+	if (stat(AUDIO_DEVICE, &st) < 0)
+		return False;
+	if (!S_ISCHR(st.st_mode))
+		return False;
+
+	return True;
+}
+
+
+/*
+ *  $B%5%&%s%I:F@8(B
+ */
+static int
+S_PlaySound(filename)
+char	*filename;
+{
+	SoundCacheBuffer	localCache;
+	int			ret;
+
+	if ((ret = S_CacheSound(filename, &localCache)) != SOUND_NO_ERROR)
+		return ret;
+	SoundTmpBuffer = localCache.soundCacheBuffer;
+	if ((ret = S_PlayCacheSound(&localCache)) != SOUND_NO_ERROR) {
+		S_FreeCacheSound(&localCache);
+		return ret;
+	}
+	return SOUND_NO_ERROR;
+}
+
+
+/*
+ *  $B%5%&%s%I$N%-%c%C%7%e2=2DG=!?IT2DG=H=Dj(B
+ */
+static Boolean
+S_IsSoundCacheAvailable()
+{
+	return True;
+}
+
+
+/*
+ *  $B%5%&%s%I$N%-%c%C%7%e2=(B
+ */
+static int
+S_CacheSound(filename, cacheBufferPtr)
+char			*filename;
+SoundCacheBuffer	*cacheBufferPtr;
+{
+	int 		soundFile;
+
+	if ((soundFile = open(filename, O_RDONLY)) < 0)
+		return SOUND_OPEN_ERROR;
+	AUDIO_INITINFO(&(cacheBufferPtr->soundBParam));
+	if ((cacheBufferPtr->soundLength = S_AuFileHeader(soundFile,
+				 &(cacheBufferPtr->soundBParam))) < 0) {
+		close(soundFile);
+		return SOUND_FILE_INVALID;
+	}
+	cacheBufferPtr->soundCacheBuffer =
+				 (char *)XtMalloc(cacheBufferPtr->soundLength);
+	read(soundFile, cacheBufferPtr->soundCacheBuffer,
+						 cacheBufferPtr->soundLength);
+	close(soundFile);
+	return SOUND_NO_ERROR;
+}
+
+
+/*
+ *  $B%-%c%C%7%e2=$5$l$?%5%&%s%I$N:F@8(B
+ */
+static int
+S_PlayCacheSound(cacheBufferPtr)
+SoundCacheBuffer	*cacheBufferPtr;
+{
+	int	tmpfd;
+	if ((tmpfd = open(AUDIO_DEVICE, O_WRONLY)) < 0) {
+		if (errno == EBUSY)
+			return SOUND_DEVICE_BUSY;
+		return SOUND_DEVICE_ERROR;
+	}
+	AudioDevice = tmpfd;
+	ioctl(AudioDevice, AUDIO_GETINFO, &AudioSaveConfig);
+	/* $B%*!<%G%#%*%U%!%$%k$K9g$o$;$F%G%P%$%9$r%;%C%H$9$k(B
+		$B%G%P%$%9L$%5%]!<%H$N7A<0$N%*!<%G%#%*%U%!%$%k$O%(%i!<(B */
+	if (ioctl(AudioDevice, AUDIO_SETINFO,
+					&(cacheBufferPtr->soundBParam)) < 0) {
+		close(AudioDevice);
+		return SOUND_DEVICE_ERROR;
+	}
+	/* $B%*!<%G%#%*%G%P%$%9$r%N%s%V%m%C%-%s%0%b!<%I$K@_Dj(B */
+	fcntl(AudioDevice, F_SETFL, fcntl(AudioDevice, F_GETFL, 0) | O_NDELAY);
+	SoundBufPtr = cacheBufferPtr->soundCacheBuffer;
+	SoundLeft = cacheBufferPtr->soundLength;
+	SoundPlayed = 0;
+	SoundTimeBytes = (cacheBufferPtr->soundBParam.play.precision / 8) *
+				cacheBufferPtr->soundBParam.play.channels *
+				cacheBufferPtr->soundBParam.play.sample_rate;
+	signal(SIGALRM, S_PlayInterval);
+	gettimeofday(&SoundStart, NULL);
+	S_PlayInterval();
+	return SOUND_NO_ERROR;
+}
+
+
+/*
+ *  $B%-%c%C%7%e2=$5$l$?%5%&%s%I$N3+J|(B
+ */
+static void
+S_FreeCacheSound(cacheBufferPtr)
+SoundCacheBuffer	*cacheBufferPtr;
+{
+	XtFree(cacheBufferPtr->soundCacheBuffer);
+}
+
+
+/*
+ *  $B%5%&%s%I4D6-$N8e;OKv(B
+ */
+static void
+S_SoundEnvDispose()
+{
+    /* $B2?$b$7$J$$(B */
+}
+
+/*
+ * SIGALRM$B$G8F$P$l$k4X?t(B
+ */
+static void
+S_PlayInterval()
+{
+	int			nbytes, timer;
+	struct itimerval	t;
+	struct timeval		now;
+
+	if (SoundLeft > 0) {
+		if ((nbytes = write(AudioDevice, SoundBufPtr, SoundLeft)) > 0) {
+			SoundPlayed += nbytes;
+			SoundLeft -= nbytes;
+			SoundBufPtr += nbytes;
+			timer = ((double)SoundPlayed / (double)SoundTimeBytes)
+								* 1000000;
+			gettimeofday(&now, NULL);
+			timer -= (now.tv_sec - SoundStart.tv_sec) * 1000000
+					+ now.tv_usec - SoundStart.tv_usec;
+			if (timer <= 0)
+				timer = 1;
+		} else {
+			timer = 1;
+			if (nbytes < 0 && errno != EBUSY)
+				SoundLeft = 0;
+		}
+		t.it_interval.tv_sec = 0;
+		t.it_interval.tv_usec = 0;
+		t.it_value.tv_sec = timer / 1000000;
+		t.it_value.tv_usec = timer % 1000000;
+		setitimer(ITIMER_REAL, &t, NULL);
+	} else {
+		if (close(AudioDevice) == -1)
+			perror("nazo\n");
+		if (SoundTmpBuffer != NULL) {
+			XtFree(SoundTmpBuffer);
+			SoundTmpBuffer = NULL;
+		}
+		signal(SIGALRM, SIG_IGN);
+	}
+}
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+# define BSWAP32(x) x = bswap32(x)
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+# define BSWAP32(x)
+#endif
+#if BYTE_ORDER == PDP_ENDIAN
+# error lose.
+#endif
+
+/*
+ * .au$B%U%!%$%k$N%X%C%@>pJs$rJV$94X?t(B
+ * $B%U%!%$%k0LCV$O%G!<%?It$N@hF,$K%;%C%H$5$l$k!#(B
+ */
+static int
+S_AuFileHeader(file, audio)
+int		file;
+audio_info_t	*audio;
+{
+	static int formattable[] = {
+		0,			0,	/* Not defined */
+		AUDIO_ENCODING_ULAW,	8,	/* 8-bit ISDN u-law */
+		AUDIO_ENCODING_LINEAR,	8,	/* 8-bit linear PCM */
+		AUDIO_ENCODING_LINEAR,	16,	/* 16-bit linear PCM */
+		AUDIO_ENCODING_LINEAR,	24,	/* 24-bit linear PCM */
+		AUDIO_ENCODING_LINEAR,	32	/* 32-bit linear PCM */
+	};
+
+	long		magic, pos, size, format, rate, chan;
+	struct stat	st;
+
+	read(file, &magic, sizeof(long));
+	BSWAP32(magic);
+	if (magic != AUDIOMAGICNUMBER)
+		return -1;
+	read(file, &pos, sizeof(long));
+	BSWAP32(pos);
+	read(file, &size, sizeof(long));
+	BSWAP32(size);
+	read(file, &format, sizeof(long));
+	BSWAP32(format);
+	read(file, &rate, sizeof(long));
+	BSWAP32(rate);
+	read(file, &chan, sizeof(long));
+	BSWAP32(chan);
+	if (format < 1 || format > 5)
+		return -1;
+	format = format * 2;
+	audio->play.encoding = formattable[format];
+	audio->play.precision = formattable[format + 1];
+	audio->play.sample_rate = rate;
+	audio->play.channels = chan;
+	lseek(file, pos, SEEK_SET);
+	fstat(file, &st);
+	return st.st_size - pos;
+}
