pkgsrc/lang/squeak/patches/patch-ak

384 lines
9.8 KiB
Text
Raw Normal View History

$NetBSD: patch-ak,v 1.1 2004/04/26 07:10:16 fredb Exp $
--- platforms/unix/vm-sound-NetBSD/sqUnixSoundNetBSD.c 1969-12-31 18:00:00.000000000 -0600
+++ platforms/unix/vm-sound-NetBSD/sqUnixSoundNetBSD.c 2004-04-25 15:05:47.000000000 -0500
@@ -0,0 +1,378 @@
+/* sqUnixSoundNetBSD.c -- sound support for NetBSD
+ *
+ * Copyright (C) 1996-2002 Ian Piumarta and other authors/contributors
+ * as listed elsewhere in this file.
+ * All rights reserved.
+ *
+ * This file is part of Unix Squeak.
+ *
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You may use and/or distribute this file ONLY as part of Squeak, under
+ * the terms of the Squeak License as described in `LICENSE' in the base of
+ * this distribution, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment to the original author(s) (and any
+ * other contributors mentioned herein) in the product documentation
+ * would be appreciated but is not required.
+ *
+ * 2. This notice must not be removed or altered in any source distribution.
+ *
+ * Using (or modifying this file for use) in any context other than Squeak
+ * changes these copyright conditions. Read the file `COPYING' in the
+ * directory `platforms/unix/doc' before proceeding with any such use.
+ *
+ * You are not allowed to distribute a modified version of this file
+ * under its original name without explicit permission to do so. If
+ * you change it, rename it.
+ *
+ * Authors: Ian.Piumarta@inria.fr, Lex Spoon <lex@cc.gatech.edu> and
+ * Frederick Bruckman <fredb@NetBSD.org>.
+ *
+ */
+
+#include "sq.h"
+#include "aio.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/audioio.h>
+#include <errno.h>
+
+
+/* Globals */
+static int auFd= -1; /* open file descriptor on AUDIODEVICE */
+static int fmtStereo; /* whether to use stereo or not */
+static int auBlockCount; /* VM's block size, in frames */
+static int auBlockSize; /* hardware blocksize, in bytes */
+static int auDuplexMode; /* 0: half duplex, !0: full duplex */
+static int auLatency; /* "fudge factor", to help keep the audio
+ hardware buffer filled */
+static int auPlaySemaIndex; /* identifier of audio system semaphore */
+static const char *auDevice; /* AUDIODEVICE, or "/dev/audio" by default */
+
+
+static int sound_AvailableSpace(void);
+
+
+static void auHandle(int fd, void *data, int flags)
+{
+ if (auFd == -1)
+ return;
+
+ if (sound_AvailableSpace() >= (auBlockSize >> 1))
+ signalSemaphoreWithIndex(auPlaySemaIndex);
+
+ aioHandle(fd, auHandle, flags);
+ return;
+}
+
+
+static int sound_Stop(void)
+{
+ if (auFd == -1)
+ return false;
+
+ aioDisable(auFd);
+ close(auFd);
+ auFd= -1;
+
+ return true;
+}
+
+
+static int sound_Start(int frameCount, int samplesPerSec, int stereo, int semaIndex)
+{
+ struct audio_info info;
+
+ /* Set some globals. */
+ auBlockCount= frameCount;
+ fmtStereo= stereo;
+ auPlaySemaIndex= semaIndex;
+
+ if (auFd != -1)
+ sound_Stop();
+
+ if ((auFd= open(auDevice, O_RDWR|O_NONBLOCK)) == -1)
+ {
+ perror(auDevice);
+ return false;
+ }
+
+ AUDIO_INITINFO(&info);
+ info.play.precision= 16;
+ info.play.encoding= AUDIO_ENCODING_SLINEAR;
+ info.play.channels= stereo ? 2 : 1;
+ info.play.sample_rate= samplesPerSec;
+ /*
+ Request desired HW blocksize to be the same as the VM's blocksize.
+ The blocksize could end up being different than what we asked for.
+ */
+ info.blocksize= auBlockSize= frameCount * (stereo ? 4 : 2);
+ info.mode= AUMODE_PLAY|AUMODE_PLAY_ALL;
+
+ if (ioctl(auFd, AUDIO_SETINFO, &info) == -1)
+ {
+ perror("AUDIO_SETINFO");
+ close(auFd);
+ auFd= -1;
+ return false;
+ }
+
+ if (info.blocksize == auBlockSize && info.hiwat > 1)
+ {
+ /*
+ Hurrah! Now tune the high- and low- water marks. Because of the
+ auLatency term, sound_AvailableSpace() will return slightly more
+ than one block after the VM returns from select(). The VM will
+ utilize the headroom to "sync up" when necessary, and thereafter
+ mostly write one full block at a time.
+ */
+ info.hiwat= (info.hiwat > 2) ? 2 : info.hiwat;
+ info.lowat= info.hiwat - 1;
+ if (ioctl(auFd, AUDIO_SETINFO, &info) == -1)
+ {
+ perror("AUDIO_SETINFO");
+ close(auFd);
+ auFd= -1;
+ return false;
+ }
+ /*
+ Set the initial fudge factor to 1/8 of the blocksize.
+ */
+ if (auLatency == 0)
+ auLatency= info.blocksize >> 3;
+ }
+ else
+ {
+ /*
+ The hardware buffer is probably too small, so just use the
+ defaults for high- and low- water marks. Don't bother with the
+ latency term, either, as we can't now sensibly calculate it.
+ */
+ warn("%s: asked for blocksize of %d, got %d!",
+ auDevice, auBlockSize, info.blocksize);
+ auBlockSize= info.blocksize;
+ }
+
+ aioEnable(auFd, 0, AIO_EXT);
+ aioHandle(auFd, auHandle, AIO_W);
+ return true;
+}
+
+
+static int sound_AvailableSpace(void)
+{
+ struct audio_info info;
+ int space;
+
+ if (auFd == -1)
+ return 0;
+
+ if (ioctl(auFd, AUDIO_GETINFO, &info) == -1)
+ {
+ perror("AUDIO_GETINFO");
+ return 0;
+ }
+
+ space= info.hiwat * info.blocksize - info.play.seek + auLatency;
+ return space;
+}
+
+
+static int sound_PlaySamplesFromAtLength(int frameCount, int arrayIndex, int startIndex)
+{
+ int size, totalWritten, written;
+ char *start;
+
+ if (auFd == -1 || frameCount == 0)
+ return 0;
+
+ start= (char *)arrayIndex + 4 * startIndex;
+ size= frameCount * (fmtStereo ? 4 : 2);
+ totalWritten= 0;
+
+ while (totalWritten < size)
+ if ((written= write(auFd, start, size)) == -1)
+ {
+ if (errno == EAGAIN)
+ /*
+ Astute listeners may now hear a "tick", but only the first
+ time the audio is started, as auLatency is preserved across
+ sound_Start() calls.
+ */
+ auLatency= auLatency >> 1;
+ else
+ perror(auDevice);
+ /*
+ In any case, bail. Typically, we've gotten an EAGAIN because
+ the auLatency was initially too high. This means the audio
+ hardware buffer is already full, so there's no sense sitting
+ here in a tight loop, while if write() failed for some other
+ reason, then we *really* want to return control to the VM.
+ */
+#ifdef AUDIO_DEBUG
+ printf("Bytes written: %d; Latency: %d\n", totalWritten, auLatency);
+#endif
+ frameCount= totalWritten/(fmtStereo ? 4 : 2);
+ return frameCount;
+ }
+ else
+ {
+ start += written;
+ size -= written;
+ totalWritten += written;
+ }
+
+#ifdef AUDIO_DEBUG
+ printf("Bytes written: %d; Latency: %d\n", totalWritten, auLatency);
+#endif
+ frameCount= totalWritten/(fmtStereo ? 4 : 2);
+ return frameCount;
+}
+
+
+static int sound_InsertSamplesFromLeadTime(int frameCount, int srcBufPtr,
+ int samplesOfLeadTime)
+{
+ /*
+ We could actually implement this with an mmap()-able audio device,
+ via double-buffering, but it doesn't seem to be worth the trouble.
+ */
+ success(false);
+ return 0;
+}
+
+
+static int sound_PlaySilence(void)
+{
+ int framesWritten;
+ char *buffer;
+
+ if (auFd == -1 || auBlockCount == 0)
+ return 0;
+
+ if ((buffer= calloc(auBlockCount, (fmtStereo ? 4 : 2))) == 0)
+ {
+ perror("calloc");
+ return 0;
+ }
+
+ framesWritten= sound_PlaySamplesFromAtLength(auBlockCount, (int)buffer, 0);
+ return framesWritten;
+}
+
+
+/*
+ Keep it clean, and try to use the simplified "audio" interface to set the
+ level, even though, due to a bug, it will do nothing on most systems older
+ than NetBSD 2.0. In that case, the user may still access the real mixer
+ controls via the command line tool "mixerctl", or various grapical mixers.
+ */
+static int sound_SetRecordLevel(int level)
+{
+ struct audio_info info;
+
+ AUDIO_INITINFO (&info);
+ info.record.gain= (level > AUDIO_MAX_GAIN) ? AUDIO_MAX_GAIN : level;
+
+ if (ioctl(auFd, AUDIO_SETINFO, &info) == -1)
+ perror("AUDIO_SETINFO");
+
+ return;
+}
+
+
+static int sound_StartRecording(int desiredSamplesPerSec, int stereo, int semaIndex)
+{
+ success(false);
+ return 0;
+}
+
+
+static int sound_StopRecording(void)
+{
+ success(false);
+ return 0;
+}
+
+
+static double sound_GetRecordingSampleRate(void)
+{
+ success(false);
+ return 0;
+}
+
+
+static int sound_RecordSamplesIntoAtLength(int buf, int startSliceIndex,
+ int bufferSizeInBytes)
+{
+ success(false);
+ return 0;
+}
+
+
+/*
+ See the comment associated with sound_SetRecordLevel().
+ */
+static void sound_Volume(double *left, double *right)
+{
+ struct audio_info info;
+
+ if (ioctl(auFd, AUDIO_GETINFO, &info) == -1)
+ {
+ perror("AUDIO_GETINFO");
+ success(false);
+ return;
+ }
+
+ *left= *right= (double)info.play.gain/AUDIO_MAX_GAIN;
+
+ return;
+}
+
+
+/*
+ This may not do anything at all. See the comment associated with
+ sound_SetRecordLevel().
+ */
+static void sound_SetVolume(double left, double right)
+{
+ struct audio_info info;
+
+ AUDIO_INITINFO (&info);
+ info.play.gain= AUDIO_MAX_GAIN * left;
+
+ if (ioctl(auFd, AUDIO_SETINFO, &info) == -1)
+ perror("AUDIO_SETINFO");
+
+ return;
+}
+
+
+#include "SqSound.h"
+
+SqSoundDefine(NetBSD);
+
+
+#include "SqModule.h"
+
+static void sound_parseEnvironment(void)
+{
+ char *ev= 0;
+ if ((ev= getenv("AUDIODEVICE"))) auDevice= strdup(ev);
+ else auDevice= strdup("/dev/audio");
+}
+
+static int sound_parseArgument(int argc, char **argv) { return 0; }
+static void sound_printUsage(void) {}
+static void sound_printUsageNotes(void) {}
+static void *sound_makeInterface(void) { return &sound_NetBSD_itf; }
+
+SqModuleDefine(sound, NetBSD);