pkgsrc/lang/squeak/patches/patch-ak
fredb 40bda8982a Update Unix VM to 3.6-3, and default image to 3.6-5429. Many improvements
and enhancements since 3.0. Notably, display and sound plugins can now be
selected at run-time, and support is added for character set conversion.
This package also contains a driver for NetBSD native audio, by yours truly.

OSS audio requires a newer interface than NetBSD emulation supports, so that
doesn't build anymore on NetBSD, though it may with third party drivers. NAS
builds on NetBSD, but doesn't work. There are new display drivers which build
selectively on linux and MacOS, and a new audio driver for MacOS. I'm marking
this package ONLY_FOR_PLATFORM=NetBSD-*-*, though, mainly because the static
PLIST that the package presently has can't reflect any of that.

This closes PR pkg/17950.
2004-04-26 07:10:16 +00:00

383 lines
9.8 KiB
Text

$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);