sound on sunos and solaris

Lex Spoon lex at cc.gatech.edu
Fri May 14 16:34:56 UTC 1999


Here's a sqUnixSound.c file that can be used on SunOS and Solaris.  It's
a bit rough, but better than nothing.  It operates as a drop-in replacement
for the OSS-based sqUnixSound.c file that is already in Ian Piumarta's
Unix distribution (if you already have OSS on your SunOS or Solaris box,
of course, then this is useless).


One thing to note: if the volume isn't right, you can either set it with
a SunOS/Solaris mixer (I don't know of any, but I haven't looked real hard),
or you can set the environment variable SQUEAK_SND_GAIN to a value between
0 and 255 inclusive.


Another note: Solaris users must add -DSOLARIS to their CFLAGS.  For
example:

	make CFLAGS="-DSOLARIS"


Without this flag, you'll get a compiler error.


Yet one more note: you might want to set your buffer size up fairly
high in SoundPlayer class>>initialize.  500 milleconds seems to work
okay.  Unfortunately, this introduces big delays....  I think it might
have to do with how frequently auPollForIO gets called, but I'm
not sure.....


Anyway, warts and all it's probably better than nothing.  Enjoy!


Lex



/* sqUnixSound.c -- sound support via Open Sound System
 *
 * Author: Ian Piumarta (ian.piumarta at inria.fr)
 *
 * Last edited: Thu Mar 11 18:12:34 1999 by piumarta (Ian Piumarta) on pingu
 *
 * Note: OSS-compatible drivers are built into the kernel on Linux.
 * Compatibility libraries are available for many other Unix systems.
 * See <http://www.opensound.com/> for details and downloads.
 */

/* TODO:
 * - allow for arbitrary combinations of AFMT_S16_LE and AFMT_S16_BE
 *   for both platform and sound card, then optimise when platform
 *   and sound card use the same format (Intel and PPC use opposite
 *   byte order).
 */

#include "sq.h"




#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#ifdef SOLARIS
#include <sys/audioio.h>
#else
#include <sun/audioio.h>
#endif


static int auFd=		-1;
static int auStereo=		0;
static int auPlaySemaIndex=	0;
static int auBufBytes=		0;   /* bogus approximation of buffer sizes */


static int auBuffersPlayed;



/* We assume that there's enough h/w buffer lead to soak up the
 * maximum input polling period in the event loop.  This should be
 * true even on slow machines (e.g. 133Mhz 386).  If not (i.e there
 * are glitches in the sound output even when Squeak is otherwise
 * idle) then #undef USE_SEMAPHORES above, and recompile to force the
 * SoundPlayer to poll every millisecond.  (NOTE: doing this grinds
 * performance into the ground!)
 */
void auPollForIO(void)
{
  if (auFd < 0) return;

  if (snd_AvailableSpace() > 0) {
    signalSemaphoreWithIndex(auPlaySemaIndex);
  }

}



/*** exported sound output functions ***/


int snd_Stop(void)
{
  if (auFd == -1) return;

  close(auFd);
  auFd= -1;

  return 0;
}


/* choose a gain (volume) level.  This can be set via the
SQUEAK_SND_GAIN environment variable.  If thevariable is unset, this
returns -1 and the system should leave the gain alone */
static int chooseGain() {
     int gain;
     char *env;
     
     env = getenv("SQUEAK_SND_GAIN");
     if(env == NULL)
	  return -1;

     if(sscanf(env, "%d", &gain) != 1)
	  return -1;

     printf("setting gain to %d\n", gain);
     
     return gain;
}


int snd_Start(int frameCount, int samplesPerSec, int stereo, int semaIndex)
{
     int bytesPerFrame=	(stereo ? 4 : 2);
     int bufferBytes=	((frameCount * bytesPerFrame) / 8) * 8;
     struct audio_info info;
     int err;
     
  
     if (auFd != -1) {
	  snd_Stop();
     }


     auPlaySemaIndex=	semaIndex;
     auStereo = stereo;


     auBufBytes = bytesPerFrame * frameCount;
     

  
     if ((auFd= open("/dev/audio", O_WRONLY)) == -1) {
	  perror("/dev/audio");
	  return false;
     }


     /* set up device */
     if(ioctl(auFd, AUDIO_GETINFO, &info)) {
	  perror("AUDIO_GETINFO");
	  goto closeAndFail;
     }
     {
	  int gain = chooseGain();
	  if(gain >= 0)
	       info.play.gain = gain;
     }
     
     info.play.precision = 16;
     info.play.encoding = AUDIO_ENCODING_LINEAR;
     info.play.channels = auStereo ? 2 : 1;
     info.play.sample_rate = samplesPerSec;

     auBuffersPlayed = info.play.eof;
  

     while((err = ioctl(auFd, AUDIO_SETINFO, &info)) && errno == EINTR)
	  ;
     

     if(err) {
	  perror("AUDIO_SETINFO");
	  goto closeAndFail;
     }

     return true;
  
closeAndFail:
     close(auFd);
     auFd= -1;
     return false;
}


int snd_AvailableSpace(void)
{
  struct audio_info info;
  int ans;
  

  if(auFd < 0)
       return 0;
  
  if(ioctl(auFd, AUDIO_GETINFO, &info)) {
       perror("AUDIO_GETINFO");
       snd_Stop();
  }

  ans = (auBufBytes * (info.play.eof - auBuffersPlayed + 2));


  return ans;
  
}


int snd_PlaySamplesFromAtLength(int frameCount, int arrayIndex, int startIndex)
{
     short *src = (short *) (arrayIndex + 4*startIndex);
     short buf[2*frameCount];
     int i;
     int bytes;
 

     if (auFd < 0) return -1;

     if(auStereo) {
	  bytes = 4 * frameCount;
	  for(i=0; i<2*frameCount; i++) {
	       buf[i] = src[i];
	  }
     }
     else {
	  bytes = 2 * frameCount;
	  for(i=0; i<frameCount; i++)
	       buf[i] = src[2*i];
     }
  
  
    
     /* write data to device from auBuf to dst */
     while (bytes > 0) {
	  int len;
	  char *pos = (char *) buf;
	  
	  len= write(auFd, pos, bytes);
	  if (len < 0) {
	       perror("/dev/audio");
	       return 0;
	  }
	  bytes-= len;
	  pos+= len;
     }

     /* add an eof marker */
     write(auFd, buf, 0);
     auBuffersPlayed += 1;
  
     return frameCount;
}


/* This primitive is impossible to implement, since the OSS is doing
 * all the necessary buffering for us and there's no way to rewrite
 * data already written.
 *
 * (We could go the whole hog and use direct DMA access to the sound
 * drivers which would allow us to mix into a buffer already partially
 * played - but: (1) OSS only supports DMA on Linux and FreeBSD
 * derivatives, (2) direct access imposes the hardware's byte order
 * and sound format, and (3) the insertSamples call is due to vanish
 * in the near future.)
 */
int snd_InsertSamplesFromLeadTime(int frameCount, int srcBufPtr,
				  int samplesOfLeadTime)
{
  return 0;	/* this is the CORRECT RESPONSE, but the image barfs */
}


int snd_PlaySilence(void)
{
     return 0;
}



/*** Recording is not yet implemented.  It's not that it's hard to
     do... I'm just feeling too lazy to do it. ***/


int snd_SetRecordLevel(int level)
{
  success(false);
  return;
}


int snd_StartRecording(int desiredSamplesPerSec, int stereo, int semaIndex)
{
  success(false);
  return;
}


int snd_StopRecording(void)
{
  return;
}


double snd_GetRecordingSampleRate(void)
{
  success(false);
  return 0.0;
}


int snd_RecordSamplesIntoAtLength(int buf, int startSliceIndex,
				  int bufferSizeInBytes)
{
  success(false);
  return 0;
}





More information about the Squeak-dev mailing list