]> git.mxchange.org Git - simgear.git/commitdiff
Initial revision.
authorcurt <curt>
Thu, 16 Jul 1998 17:48:11 +0000 (17:48 +0000)
committercurt <curt>
Thu, 16 Jul 1998 17:48:11 +0000 (17:48 +0000)
22 files changed:
Audio/CHANGES [new file with mode: 0644]
Audio/Makefile.am [new file with mode: 0644]
Audio/NOTICE [new file with mode: 0644]
Audio/README [new file with mode: 0644]
Audio/README.freebsd [new file with mode: 0644]
Audio/README.linux [new file with mode: 0644]
Audio/README.openbsd [new file with mode: 0644]
Audio/README.sgi [new file with mode: 0644]
Audio/README.unix [new file with mode: 0644]
Audio/README.win [new file with mode: 0644]
example/Makefile.am [new file with mode: 0644]
example/example.cxx [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/sl.h [new file with mode: 0644]
src/slDSP.cxx [new file with mode: 0644]
src/slEnvelope.cxx [new file with mode: 0644]
src/slPortability.h [new file with mode: 0644]
src/slSample.cxx [new file with mode: 0644]
src/slSamplePlayer.cxx [new file with mode: 0644]
src/slScheduler.cxx [new file with mode: 0644]
src/sm.h [new file with mode: 0644]
src/smMixer.cxx [new file with mode: 0644]

diff --git a/Audio/CHANGES b/Audio/CHANGES
new file mode 100644 (file)
index 0000000..7c6a79a
--- /dev/null
@@ -0,0 +1,119 @@
+
+/**********************************************\
+*                                              *
+*                W A R N I N G                 *
+*                                              *
+* This file is now kept in reverse chronolog-  *
+* ical order so recent changes are now at the  *
+* top.                                         *
+*                                              *
+\**********************************************/
+
+* 6th  July 1998 -- Fixed an initialisation problem when
+                    slScheduler was not a static/global.
+
+                    Tom Knienieder's port to SGI/IRIX is now
+                    working, documentation updated to reflect that.
+
+* 16th June 1998 -- Added some slPortability.h fixes for
+                    FreeBSD and the Cygnus WIN32 compiler.
+                    Many thanks to Curt.
+
+* 14th June 1998 -- Tom Knienieder's port to OpenBSD is now
+                    working, documentation updated to reflect that.
+                    Tom's improved Makefiles included, also some
+                    example sound samples that were accidentally
+                    left out of the release are now present.
+                    A couple of typo's in the WIN32 section
+                    have been fixed. The top level Makefile
+                    now requires you to type 'make linux',
+                    'make win' or 'make openbsd'.
+
+* 13th June 1998 -- Tom Knienieder's port to WIN32 engine is now
+                    working, documentation updated to reflect that
+                    revised status. Some default constructor parameters
+                    have changed, slDSP no longer supports setRate/setBps/setStereo.
+                    You now have to delete the slDSP and recreate it with
+                    new parameters. This makes porting a little easier.
+                    'sound_test' renamed 'example'.
+
+* 7th  June 1998 -- Volume envelopes (and inverse volume envelopes)
+                    now work correctly. Pan envelopes won't work
+                    until stereo is implemented. Pitch and filter
+                    envelopes turn out to be a major pain to implement
+                    with the present slSceduler/slSamplePlayer interface,
+                    so some significant internal changes are to be
+                    expected.
+
+                    Changed the CHANGES file to be in reverse
+                    chronological order.
+
+                    This version is officially  SL v0.3 (beta)
+*  3rd June 1998 -- Moved sample program and it's data files into
+                    'example', moved documents into 'doc' and sources
+                    into 'src'. Final library goes into 'lib'.
+
+                    The entire preempting mechanism was broken -
+                    now it's fixed.
+                    Added a callback mechanism that allows
+                    applications to know when a sound
+                    loops, finishes playing, is pre-empted, etc.
+
+                    New mechanisms added to stop/pause/resume a
+                    playing sample.
+                    All the documentation - and some of the code -
+                    for slEnvelopes has been added, they don't
+                    work yet - so don't bother with them for now.
+
+                    Made some code a little more bullet-proof.
+                    slSample's are now reference-counted so you
+                    can't accidentally delete one while it's
+                    playing without getting a FATAL error.
+
+* 2nd  June 1998 -- Fixed bug in initialisation that prevented SL
+                    from functioning correctly in the case were there
+                    is no sound card present.
+
+                    This version is officially  SL v0.2 (beta)
+
+* 1st  June 1998 -- Split library into two parts - libsm and
+                    libsl. libsm contains only the Mixer class
+                    since it is likely to be hard to port to
+                    a lot of non-OSS systems - and most programs
+                    won't need it anyway. Hence the documentation
+                    has blossomed into three files and all the
+                    'slMixer' references have turned into 'smMixer'.
+                    Also, I finally got a hold of the OSS documentation,
+                    which is a lot more complete - and straightened
+                    me out on a few points. slDSP has changed
+                    (internally) somewhat as a result and in particular,
+                    you can no longer mess with the sampling rate,
+                    stereo and bps settings after the slDSP or
+                    slScheduler has been created. This also allows the
+                    scheduler to enforce it's rule about only mono/8bps
+                    operations.
+
+                    I also added an 'autoMatch' function to the slSample
+                    class to automagically match incoming samples to the
+                    current slDSP/slScheduler. This makes using the library
+                    a lot less painful and error-prone.
+                    This version is officially  SL v0.1 (beta)
+                    We need a better name!
+
+* 30th May  1998 -- Almost total rewrite, library can now
+                    play multiple sounds without interruption,
+                    supports '.WAV' and '.AU' file formats as
+                    well as raw binary files. Able to copy with
+                    much shorter safetyMargin on sound buffers,
+                    and play without using the 'stop' call.
+                    All class and external symbols now begin
+                    with 'sl' or 'SL'. HTML documentation now
+                    available.
+
+* 27th May  1998 -- First hack
+
diff --git a/Audio/Makefile.am b/Audio/Makefile.am
new file mode 100644 (file)
index 0000000..835577f
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src example
diff --git a/Audio/NOTICE b/Audio/NOTICE
new file mode 100644 (file)
index 0000000..ba95093
--- /dev/null
@@ -0,0 +1,9 @@
+NOTICE:  This Sound Library (SL) distribution contains source code that is
+placed into the public domain without copyright. These programs are freely
+distributable without licensing fees.  These programs are provided without
+guarantee or warrantee expressed or implied. 
+
+If you use SL in a commercial or shareware product, it would be nice if you
+gave credit where it is due.  If you make any modifications or improvements
+to SL, I would greatly appreciate a copy of the improved code.
+
diff --git a/Audio/README b/Audio/README
new file mode 100644 (file)
index 0000000..8bf6b4d
--- /dev/null
@@ -0,0 +1,9 @@
+
+Hi!
+
+  This is the fifth prototype of Steve's 'SL' sound library.
+
+  Check out 'CHANGES' and the new HTML documentation.
+
+Steve
+
diff --git a/Audio/README.freebsd b/Audio/README.freebsd
new file mode 100644 (file)
index 0000000..540c00e
--- /dev/null
@@ -0,0 +1,13 @@
+
+Building SL for Linux.
+~~~~~~~~~~~~~~~~~~~~~~
+
+   % make freebsd
+   % su root
+   % make install
+
+...that's all folks.
+
+Header  files   go into /usr/include/SL (analogous to /usr/include/GL for graphics)
+Library file(s) go into /usr/lib
+
diff --git a/Audio/README.linux b/Audio/README.linux
new file mode 100644 (file)
index 0000000..7df00e8
--- /dev/null
@@ -0,0 +1,13 @@
+
+Building SL for Linux.
+~~~~~~~~~~~~~~~~~~~~~~
+
+   % make linux
+   % su root
+   % make install
+
+...that's all folks.
+
+Header  files   go into /usr/include/SL (analogous to /usr/include/GL for graphics)
+Library file(s) go into /usr/lib
+
diff --git a/Audio/README.openbsd b/Audio/README.openbsd
new file mode 100644 (file)
index 0000000..9ef788f
--- /dev/null
@@ -0,0 +1,13 @@
+
+Building SL for OpenBSD.
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+   % make openbsd
+   % su root
+   % make install
+
+...that's all folks.
+
+Header  files   go into /usr/include/SL (analogous to /usr/include/GL for graphics)
+Library file(s) go into /usr/lib
+
diff --git a/Audio/README.sgi b/Audio/README.sgi
new file mode 100644 (file)
index 0000000..844c9c9
--- /dev/null
@@ -0,0 +1,13 @@
+
+Building SL for SGI.
+~~~~~~~~~~~~~~~~~~~~~~
+
+   % make sgi
+   % su root
+   % make install
+
+...that's all folks.
+
+Header  files   go into /usr/include/SL (analogous to /usr/include/GL for graphics)
+Library file(s) go into /usr/lib
+
diff --git a/Audio/README.unix b/Audio/README.unix
new file mode 100644 (file)
index 0000000..771e856
--- /dev/null
@@ -0,0 +1,20 @@
+Building SL for UNIX
+~~~~~~~~~~~~~~~~~~~~
+
+If your UNIX box is Linux or OpenBSD then
+check out README.linux or README.openbsd.
+
+If your UNIX box supports OSS (the Open
+Sound System) then in principal, you should
+only need to type:
+
+  % make oss
+  % su root
+  % make install
+
+...however, your milage may vary. If you succeed
+in getting a non-Linux, non-OpenBSD version to
+work, I'd like to hear about it.
+
+          Steve Baker  <sjbaker1@airmail.net>
+
diff --git a/Audio/README.win b/Audio/README.win
new file mode 100644 (file)
index 0000000..a9d5282
--- /dev/null
@@ -0,0 +1,15 @@
+
+Building SL for win32 (msvc)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+   C:>nmake win32
+
+
+don't forget to set the environment !
+
+example:
+
+set include=c:\msdev\include;
+set lib=c:\msdev\lib
+
+path c:\msdev\bin;c:\bin;c:\winnt;......
diff --git a/example/Makefile.am b/example/Makefile.am
new file mode 100644 (file)
index 0000000..bc0d25e
--- /dev/null
@@ -0,0 +1,13 @@
+bin_PROGRAMS = example
+
+example_SOURCES = example.cxx
+
+example_LDADD = \
+       $(top_builddir)/Lib/Audio/src/libsl.la \
+       $(top_builddir)/Lib/Audio/src/libsm.la
+
+INCLUDES += -I$(top_builddir)/Lib/Audio/src
+
+if ENABLE_WIN32_AUDIO
+LIBS += -lwinmm
+endif
diff --git a/example/example.cxx b/example/example.cxx
new file mode 100644 (file)
index 0000000..ae51978
--- /dev/null
@@ -0,0 +1,89 @@
+
+
+#include "sl.h"
+#include "sm.h"
+#include <math.h>
+
+/*
+  Construct a sound scheduler and a mixer.
+*/
+
+slScheduler sched ( 8000 ) ;
+smMixer mixer ;
+
+int main ()
+{
+  mixer . setMasterVolume ( 30 ) ;
+  sched . setSafetyMargin ( 0.128 ) ;
+
+  /* Just for fun, let's make a one second synthetic engine sample... */
+
+  Uchar buffer [ 8000 ] ;
+
+  for ( int i = 0 ; i < 8000 ; i++ )
+  {
+    /* Sum some sin waves and convert to range 0..1 */
+
+    float level = ( sin ( (double) i * 2.0 * M_PI / (8000.0/ 50.0) ) +
+                    sin ( (double) i * 2.0 * M_PI / (8000.0/149.0) ) +
+                    sin ( (double) i * 2.0 * M_PI / (8000.0/152.0) ) +
+                    sin ( (double) i * 2.0 * M_PI / (8000.0/192.0) )
+                  ) / 8.0f + 0.5f ;
+
+    /* Convert to unsigned byte */
+
+    buffer [ i ] = (Uchar) ( level * 255.0 ) ;
+  }
+
+  /* Set up four samples and a loop */
+
+  slSample  *s = new slSample ( buffer, 8000 ) ;
+  slSample *s1 = new slSample ( "scream.ub", & sched ) ;
+  slSample *s2 = new slSample ( "zzap.wav" , & sched ) ;
+  slSample *s3 = new slSample ( "cuckoo.au", & sched ) ;
+  slSample *s4 = new slSample ( "wheeee.ub", & sched ) ;
+
+  /* Mess about with some of the samples... */
+
+  s1 -> adjustVolume ( 2.2  ) ;
+  s2 -> adjustVolume ( 0.5  ) ;
+  s3 -> adjustVolume ( 0.2  ) ;
+
+  /* Play the engine sample continuously. */
+
+  sched . loopSample ( s ) ;
+
+  int tim = 0 ;  /* My periodic event timer. */
+
+  while ( SL_TRUE )
+  {
+    tim++ ;  /* Time passes */
+
+    if ( tim % 200 == 0 ) sched.playSample ( s1 ) ;
+    if ( tim % 180 == 0 ) sched.playSample ( s2 ) ;
+    if ( tim % 150 == 0 ) sched.playSample ( s3 ) ;
+    if ( tim % 120 == 0 ) sched.playSample ( s4 ) ;
+
+    /*
+      For the sake of realism, I'll delay for 1/30th second to
+      simulate a graphics update process.
+    */
+
+#ifdef WIN32
+    Sleep ( 1000 / 30 ) ;      /* 30Hz */
+#elif defined(sgi)
+    sginap( 3 );               /* ARG */
+#else
+    usleep ( 1000000 / 30 ) ;  /* 30Hz */
+#endif
+
+    /*
+      This would normally be called just before the graphics buffer swap
+      - but it could be anywhere where it's guaranteed to get called
+      fairly often.
+    */
+
+    sched . update () ;
+  }
+}
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..72aa7df
--- /dev/null
@@ -0,0 +1,12 @@
+libdir = ${exec_prefix}/lib
+
+lib_LTLIBRARIES = libsl.la libsm.la
+
+libsl_la_SOURCES = \
+       sl.h slPortability.h \
+       slDSP.cxx slSample.cxx slEnvelope.cxx \
+       slSamplePlayer.cxx slScheduler.cxx
+
+libsm_la_SOURCES = sm.h slPortability.h smMixer.cxx
+
+INCLUDES += -I$(top_builddir) -I.
diff --git a/src/sl.h b/src/sl.h
new file mode 100644 (file)
index 0000000..79b63e6
--- /dev/null
+++ b/src/sl.h
@@ -0,0 +1,635 @@
+
+#ifndef __SL_H__
+#define __SL_H__ 1
+
+#include "slPortability.h"
+
+#ifdef SL_USING_OSS_AUDIO
+#define SLDSP_DEFAULT_DEVICE "/dev/dsp"
+#elif defined(WIN32)
+#define SLDSP_DEFAULT_DEVICE "dsp"     
+#elif defined(__OpenBSD__)
+#define SLDSP_DEFAULT_DEVICE "/dev/audio"
+#elif defined(sgi)
+#define SLDSP_DEFAULT_DEVICE "dsp"             // dummy ...
+#else
+#error "Port me !"
+#endif
+
+# define SL_TRUE  1
+# define SL_FALSE 0
+
+typedef unsigned char  Uchar  ;
+typedef unsigned short Ushort ;
+
+#define SL_DEFAULT_SAMPLING_RATE 11025
+
+class slSample       ;
+class slSamplePlayer ;
+class slEnvelope     ;
+class slScheduler    ;
+class slDSP          ;
+
+class slDSP
+{
+private:
+
+  int stereo ;
+  int rate ;
+  int bps ;
+
+  int error ;
+  int fd ;
+
+#ifdef __OpenBSD__
+  audio_info_t    ainfo;        // ioctl structure
+  audio_offset_t  audio_offset; // offset in audiostream
+  long            counter;      // counter-written packets
+#elif defined(SL_USING_OSS_AUDIO)
+  audio_buf_info buff_info ;
+#elif defined(sgi)
+  ALconfig        config;       // configuration stuff
+  ALport          port;         // .. we are here 
+#endif
+
+
+#ifndef WIN32
+  int ioctl ( int cmd, int param = 0 )
+  {
+    if ( error ) return param ;
+
+    if ( ::ioctl ( fd, cmd, & param ) == -1 )
+    {
+      perror ( "slDSP: ioctl" ) ;
+      error = SL_TRUE ;
+    }
+
+    return param ;
+  }
+
+#elif defined(WIN32)
+
+   HWAVEOUT       hWaveOut;      // device handle 
+   WAVEFORMATEX   Format;        // open needs this
+   MMTIME         mmt;          // timing 
+   WAVEHDR        wavehdr[ 3 ];  // for round robin ..
+   int            curr_header;   // index of actual wavehdr
+   long           counter;       // counter-written packets
+
+#endif
+
+  void open ( char *device, int _rate, int _stereo, int _bps ) ;
+  void close () ;
+  void getBufferInfo () ;
+  void write ( void *buffer, size_t length ) ;
+
+protected:
+
+  void setError () { error = SL_TRUE ; }
+  int getDriverBufferSize () ;
+
+public:
+
+  slDSP ( int _rate = SL_DEFAULT_SAMPLING_RATE,
+          int _stereo = SL_FALSE, int _bps = 8 )
+  {
+    open ( SLDSP_DEFAULT_DEVICE, _rate, _stereo, _bps ) ;
+  } 
+
+  slDSP ( char *device, int _rate = SL_DEFAULT_SAMPLING_RATE,
+          int _stereo = SL_FALSE, int _bps = 8 )
+  {
+    open ( device, _rate, _stereo, _bps ) ;
+  } 
+
+ ~slDSP () { close () ; }
+  
+  float secondsRemaining () ;
+  float secondsUsed () ;
+
+  void play ( void *buffer, size_t length ) { write ( buffer, length ) ; } 
+
+  int not_working () { return error ; }
+
+  int getBps   () { return bps    ; }
+  int getRate  () { return rate   ; }
+  int getStereo() { return stereo ; }
+
+  void sync () ;
+  void stop () ;
+} ;
+
+
+class slSample
+{
+  int    ref_count ;
+protected:
+
+  char  *comment;
+  int    rate   ;
+  int    bps    ;
+  int    stereo ;
+
+  Uchar *buffer ;
+  int    length ;
+
+  void init ()
+  {
+    ref_count = 0 ;
+    comment = NULL  ;
+    buffer  = NULL  ;
+    length  = 0     ;
+    rate    = SL_DEFAULT_SAMPLING_RATE ;
+    bps     = 8     ;
+    stereo  = SL_FALSE ;
+  }
+
+public:
+
+  slSample () { init () ; }
+
+  slSample ( Uchar *buff, int leng )
+  {
+    init () ;
+    setBuffer ( buff, leng ) ;
+  }
+
+  slSample ( char *fname, class slDSP *dsp = NULL )
+  {
+    init () ;
+    loadFile ( fname ) ;
+    autoMatch ( dsp ) ;
+  }
+
+ ~slSample ()
+  {
+    if ( ref_count != 0 )
+    {
+      fprintf ( stderr,
+        "slSample: FATAL ERROR - Application deleted a sample while it was playing.\n" ) ;
+      exit ( 1 ) ;
+    }
+
+    delete buffer ;
+  }
+  
+  void ref   () { ref_count++ ; }
+  void unRef () { ref_count-- ; }
+
+  int getPlayCount () { return ref_count ; }
+
+  char  *getComment () { return comment ; }
+
+  void   setComment ( char *nc )
+  {
+    delete comment ;
+    comment = new char [ strlen ( nc ) + 1 ] ;
+    strcpy ( comment, nc ) ;
+  }
+
+  Uchar *getBuffer () { return buffer ; }
+  int    getLength () { return length ; }
+
+  void  autoMatch ( slDSP *dsp ) ;
+
+  void   setBuffer ( Uchar *buff, int leng )
+  {
+    delete buffer ;
+
+    buffer = new Uchar [ leng ] ;
+
+    if ( buff != NULL )
+      memcpy ( buffer, buff, leng ) ;
+
+    length = leng ;
+  }
+
+  /* These routines only set flags - use changeXXX () to convert a sound */
+
+  void setRate   ( int r ) { rate   = r ; }
+  void setBps    ( int b ) { bps    = b ; }
+  void setStereo ( int s ) { stereo = s ; }
+
+  int  getRate   ()        { return rate   ; }
+  int  getBps    ()        { return bps    ; }
+  int  getStereo ()        { return stereo ; }
+
+  float getDuration ()     { return (float) getLength() /
+                                    (float) ( (getStereo()?2.0f:1.0f)*
+                                              (getBps()/8.0f)*getRate() ) ; }
+
+  int loadFile    ( char *fname ) ;
+
+  int loadRawFile ( char *fname ) ;
+  int loadAUFile  ( char *fname ) ;
+  int loadWavFile ( char *fname ) ;
+
+  void changeRate   ( int r ) ;
+  void changeBps    ( int b ) ;
+  void changeStereo ( int s ) ;
+
+  void adjustVolume ( float vol ) ;
+
+  void print ( FILE *fd )
+  {
+    if ( buffer == NULL )
+    {
+      fprintf ( fd, "Empty sample buffer\n" ) ;
+    }
+    else
+    {
+      fprintf ( fd, "\"%s\"\n",(getComment() == NULL ||
+                                getComment()[0]=='\0') ? "Sample" : comment  ) ;
+      fprintf ( fd, "%s, %d bits per sample.\n",
+                           getStereo() ? "Stereo" : "Mono", getBps() ) ;
+      fprintf ( fd, "%gKHz sample rate.\n", (float) getRate() / 1000.0f ) ;
+      fprintf ( fd, "%d bytes of samples == %g seconds duration.\n", getLength(), getDuration() ) ;
+    }
+  }
+} ;
+
+
+enum slSampleStatus
+{
+  SL_SAMPLE_WAITING,  /* Sound hasn't started playing yet */
+  SL_SAMPLE_RUNNING,  /* Sound has started playing */
+  SL_SAMPLE_DONE   ,  /* Sound is complete */
+  SL_SAMPLE_PAUSED    /* Sound hasn't started playing yet */
+} ;
+
+
+enum slPreemptMode
+{
+  SL_SAMPLE_CONTINUE,  /* Don't allow yourself to be preempted   */
+  SL_SAMPLE_ABORT   ,  /* Abort playing the sound when preempted */
+  SL_SAMPLE_RESTART ,  /* Restart the sound when load permits    */
+  SL_SAMPLE_MUTE    ,  /* Continue silently until load permits   */
+  SL_SAMPLE_DELAY      /* Pause until load permits               */
+} ;
+
+
+enum slReplayMode
+{
+  SL_SAMPLE_LOOP,      /* Loop sound so that it plays forever */
+  SL_SAMPLE_ONE_SHOT   /* Play sound just once */
+} ;
+
+enum slEvent
+{
+  SL_EVENT_COMPLETE,  /* Sound finished playing */
+  SL_EVENT_LOOPED,    /* Sound looped back to the start */
+  SL_EVENT_PREEMPTED  /* Sound was preempted */
+} ;
+
+typedef void (*slCallBack) ( slSample *, slEvent, int ) ;
+
+class slEnvelope
+{
+  float *time  ;
+  float *value ;
+  int   nsteps ;
+  int   ref_count ;
+
+  slReplayMode replay_mode ;
+
+  int getStepDelta ( float *_time, float *delta ) ;
+
+public:
+
+  slEnvelope ( int _nsteps, slReplayMode _rm, float *_times, float *_values )
+  {
+    ref_count = 0 ;
+    nsteps = _nsteps ;
+    time  = new float [ nsteps ] ;
+    value = new float [ nsteps ] ;
+    memcpy ( time , _times , sizeof(float) * nsteps ) ;
+    memcpy ( value, _values, sizeof(float) * nsteps ) ;
+
+    replay_mode = _rm ;
+  }
+
+
+  slEnvelope ( int _nsteps = 1, slReplayMode _rm = SL_SAMPLE_ONE_SHOT )
+  {
+    ref_count = 0 ;
+    nsteps = _nsteps ;
+    time  = new float [ nsteps ] ;
+    value = new float [ nsteps ] ;
+
+    for ( int i = 0 ; i < nsteps ; i++ )
+      time [ i ] = value [ i ] = 0.0 ;
+
+    replay_mode = _rm ;
+  }
+ ~slEnvelope ()
+  {
+    if ( ref_count != 0 )
+    {
+      fprintf ( stderr,
+        "slEnvelope: FATAL ERROR - Application deleted an envelope while it was playing.\n" ) ;
+      exit ( 1 ) ;
+    }
+
+    delete time ;
+    delete value ;
+  }
+
+  void ref   () { ref_count++ ; }
+  void unRef () { ref_count-- ; }
+
+  int getPlayCount () { return ref_count ; }
+
+  void setStep ( int n, float _time, float _value )
+  {
+    if ( n >= 0 && n < nsteps )
+    {
+      time  [ n ] = _time  ;
+      value [ n ] = _value ;
+    }
+  }
+
+  float getStepValue ( int s ) { return value [ s ] ; }
+  float getStepTime  ( int s ) { return time  [ s ] ; }
+
+  int   getNumSteps  () { return nsteps ; }
+
+  float getValue ( float _time ) ;
+
+  void applyToVolume    ( Uchar *dst, Uchar *src, int nframes, int start ) ;
+  void applyToInvVolume ( Uchar *dst, Uchar *src, int nframes, int start ) ;
+} ;
+
+#define SL_MAX_PRIORITY  16
+#define SL_MAX_SAMPLES   16
+#define SL_MAX_CALLBACKS (SL_MAX_SAMPLES * 2)
+#define SL_MAX_ENVELOPES 4
+
+enum slEnvelopeType
+{
+  SL_PITCH_ENVELOPE , SL_INVERSE_PITCH_ENVELOPE ,
+  SL_VOLUME_ENVELOPE, SL_INVERSE_VOLUME_ENVELOPE,
+  SL_FILTER_ENVELOPE, SL_INVERSE_FILTER_ENVELOPE,
+  SL_PAN_ENVELOPE   , SL_INVERSE_PAN_ENVELOPE   ,
+  SL_ECHO_ENVELOPE  , SL_INVERSE_ECHO_ENVELOPE  ,
+
+  SL_NULL_ENVELOPE
+} ;
+
+struct slPendingCallBack
+{
+  slCallBack callback ;
+  slSample  *sample   ;
+  slEvent    event    ;
+  int        magic    ;
+} ;
+
+class slSamplePlayer
+{
+  int            lengthRemaining ;
+  Uchar         *bufferPos       ;
+  slSample      *sample          ;
+
+  slEnvelope    *env            [ SL_MAX_ENVELOPES ] ;
+  slEnvelopeType env_type       [ SL_MAX_ENVELOPES ] ;
+  int            env_start_time [ SL_MAX_ENVELOPES ] ;
+
+  slReplayMode   replay_mode     ;
+  slPreemptMode  preempt_mode    ;
+  slSampleStatus status          ;
+  int            priority        ;
+
+  slCallBack     callback ;
+  int            magic ;
+
+public:
+
+  slSamplePlayer ( slSample *s, slReplayMode  rp_mode = SL_SAMPLE_ONE_SHOT, 
+                  int pri = 0, slPreemptMode pr_mode = SL_SAMPLE_DELAY,
+                   int _magic = 0, slCallBack cb = NULL )
+  {
+    magic           = _magic ;
+    sample          = s ;
+    callback        = cb ;
+
+    for ( int i = 0 ; i < SL_MAX_ENVELOPES ; i++ )
+    {
+      env [ i ] = NULL ;
+      env_type [ i ] = SL_NULL_ENVELOPE ;
+    }
+
+    if ( sample ) sample -> ref () ;
+
+    reset () ;
+
+    replay_mode     = rp_mode ;
+    preempt_mode    = pr_mode ;
+    priority        = pri ;
+  }
+
+  ~slSamplePlayer () ;
+
+  int getAmountLeft ()
+  {
+    return lengthRemaining ;
+  }
+
+  slPreemptMode getPreemptMode () { return preempt_mode ; }
+
+  int getPriority ()
+  {
+    return ( isRunning() &&
+             preempt_mode == SL_SAMPLE_CONTINUE ) ? (SL_MAX_PRIORITY+1) :
+                                                               priority ;
+  }
+
+  int preempt ( int delay ) ;
+  
+  void addEnvelope ( int i, slEnvelope *_env, slEnvelopeType _type ) ;
+
+  void pause ()
+  {
+    if ( status != SL_SAMPLE_DONE )
+      status = SL_SAMPLE_PAUSED ;
+  }
+
+  void resume ()
+  {
+    if ( status == SL_SAMPLE_PAUSED )
+      status = SL_SAMPLE_RUNNING ;
+  }
+
+  void reset ()
+  {
+    status = SL_SAMPLE_WAITING ;
+    lengthRemaining = sample->getLength () ;
+    bufferPos       = sample->getBuffer () ;
+  } 
+
+  void start ()
+  {
+    status = SL_SAMPLE_RUNNING ;
+    lengthRemaining = sample->getLength () ;
+    bufferPos       = sample->getBuffer () ;
+  } 
+
+  void stop ()
+  {
+    status = SL_SAMPLE_DONE ;
+    lengthRemaining = 0    ;
+    bufferPos       = NULL ;
+  } 
+
+  int       getMagic  () { return magic  ; }
+  slSample *getSample () { return sample ; }
+
+  int isWaiting () { return status == SL_SAMPLE_WAITING ; } 
+  int isPaused  () { return status == SL_SAMPLE_PAUSED  ; } 
+  int isRunning () { return status == SL_SAMPLE_RUNNING ; } 
+  int isDone    () { return status == SL_SAMPLE_DONE    ; }
+
+  void   skip ( int nframes ) ;
+  Uchar *read ( int nframes, Uchar *spare1, Uchar *spare2 ) ;
+} ;
+
+
+class slScheduler : public slDSP
+{
+  slPendingCallBack pending_callback [ SL_MAX_CALLBACKS ] ;
+  int num_pending_callbacks ;
+
+  float safety_margin ;
+  int mixer_buffer_size ;
+  Uchar *mixer_buffer ;
+  Uchar *mixer ;
+  int amount_left ;
+
+  slSamplePlayer *samplePlayer [ SL_MAX_SAMPLES ] ;
+
+  Uchar *spare_buffer1 [ 3 ] ;
+  Uchar *spare_buffer2 [ 3 ] ;
+  
+  void init () ;
+
+  Uchar *mergeBlock ( Uchar *d ) ;
+  Uchar *mergeBlock ( Uchar *d, slSamplePlayer *spa ) ;
+  Uchar *mergeBlock ( Uchar *d, slSamplePlayer *spa,
+                                slSamplePlayer *spb ) ;
+  Uchar *mergeBlock ( Uchar *d, slSamplePlayer *spa,
+                                slSamplePlayer *spb,
+                                slSamplePlayer *spc ) ;
+  void mixBuffer () ;
+  void mixBuffer ( slSamplePlayer *a ) ;
+  void mixBuffer ( slSamplePlayer *a,
+                   slSamplePlayer *b ) ;
+  void mixBuffer ( slSamplePlayer *a,
+                   slSamplePlayer *b,
+                   slSamplePlayer *c ) ;
+
+  Uchar mix ( Uchar a, Uchar b )
+  {
+    register int r = a + b - 0x80 ;
+    return ( r > 255 ) ? 255 :
+           ( r <  0  ) ?  0  : r ;
+  }
+
+  Uchar mix ( Uchar a, Uchar b, Uchar c )
+  {
+    register int r = a + b + c - 0x80 - 0x80 ;
+    return ( r > 255 ) ? 255 :
+           ( r <  0  ) ?  0  : r ;
+  }
+
+  void realUpdate ( int dump_first = SL_FALSE ) ;
+
+  void initBuffers () ;
+
+  int now ;
+
+  static slScheduler *current ;
+
+public:
+
+  slScheduler ( int _rate = SL_DEFAULT_SAMPLING_RATE ) : slDSP ( _rate, SL_FALSE, 8 ) { init () ; }
+  slScheduler ( char *device,
+                int _rate = SL_DEFAULT_SAMPLING_RATE ) : slDSP ( device, _rate, SL_FALSE, 8 ) { init () ; }
+ ~slScheduler () ;
+
+  static slScheduler *getCurrent () { return current ; }
+
+  int   getTimeNow     () { return now ; }
+  float getElapsedTime ( int then ) { return (float)(now-then)/(float)getRate() ; }
+
+  void flushCallBacks () ;
+  void addCallBack    ( slCallBack c, slSample *s, slEvent e, int m ) ;
+
+  void update     () { realUpdate ( SL_FALSE ) ; }
+  void dumpUpdate () { realUpdate ( SL_TRUE  ) ; }
+
+  void addSampleEnvelope ( slSample *s = NULL, int magic = 0,
+                           int slot = 1, slEnvelope *e = NULL, 
+                           slEnvelopeType t =  SL_VOLUME_ENVELOPE )
+  {
+    for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
+      if ( samplePlayer [ i ] != NULL &&
+           ( s  == NULL || samplePlayer [ i ] -> getSample () ==   s   ) &&
+           ( magic == 0 || samplePlayer [ i ] -> getMagic  () == magic ) )
+        samplePlayer [ i ] -> addEnvelope ( slot, e, t ) ;
+  }
+  void resumeSample ( slSample *s = NULL, int magic = 0 )
+  {
+    for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
+      if ( samplePlayer [ i ] != NULL &&
+           ( s  == NULL || samplePlayer [ i ] -> getSample () ==   s   ) &&
+           ( magic == 0 || samplePlayer [ i ] -> getMagic  () == magic ) )
+        samplePlayer [ i ] -> resume () ;
+  }
+  void pauseSample ( slSample *s = NULL, int magic = 0 )
+  {
+    for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
+      if ( samplePlayer [ i ] != NULL &&
+           ( s  == NULL || samplePlayer [ i ] -> getSample () ==   s   ) &&
+           ( magic == 0 || samplePlayer [ i ] -> getMagic  () == magic ) )
+        samplePlayer [ i ] -> pause () ;
+  }
+  void stopSample ( slSample *s = NULL, int magic = 0 )
+  {
+    for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
+      if ( samplePlayer [ i ] != NULL &&
+           ( s  == NULL || samplePlayer [ i ] -> getSample () ==   s   ) &&
+           ( magic == 0 || samplePlayer [ i ] -> getMagic  () == magic ) )
+        samplePlayer [ i ] -> stop () ;
+  }
+  int loopSample ( slSample *s, int pri = 0, slPreemptMode mode = SL_SAMPLE_MUTE, int magic = 0, slCallBack cb = NULL )
+  {
+    for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
+      if ( samplePlayer [ i ] == NULL )
+      {
+        samplePlayer [ i ] = new slSamplePlayer ( s, SL_SAMPLE_LOOP, pri, mode, magic, cb ) ;
+        return i ;
+      }
+
+    return -1 ;
+  }
+
+  int playSample ( slSample *s, int pri = 1, slPreemptMode mode = SL_SAMPLE_ABORT, int magic = 0, slCallBack cb = NULL )
+  {
+    for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
+      if ( samplePlayer [ i ] == NULL )
+      {
+        samplePlayer [ i ] = new slSamplePlayer ( s, SL_SAMPLE_ONE_SHOT, pri, mode, magic, cb ) ;
+        return SL_TRUE ;
+      }
+
+    return SL_FALSE ;
+  }
+
+  void setSafetyMargin ( float seconds ) { safety_margin = seconds ; }
+} ;
+
+#endif
+
diff --git a/src/slDSP.cxx b/src/slDSP.cxx
new file mode 100644 (file)
index 0000000..fbb0da3
--- /dev/null
@@ -0,0 +1,663 @@
+
+#include "sl.h"
+
+static int init_bytes ;
+
+#ifdef SL_USING_OSS_AUDIO
+
+/* ------------------------------------------------------------ */
+/* OSSAUDIO - Linux, FreeBSD, etc                               */
+/* ------------------------------------------------------------ */
+
+void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
+{
+  fd = ::open ( device, O_WRONLY ) ;
+
+  if ( fd < 0 )
+  {
+    perror ( "slDSP: open" ) ;
+    error = SL_TRUE ;
+
+    stereo     = SL_FALSE ;
+    bps        =    1     ;
+    rate       =  8000    ;
+    init_bytes =    0     ;
+  }
+  else
+  {
+    error = SL_FALSE ;
+
+    /* Set up a driver fragment size of 1024 (ie 2^10) */
+
+    ioctl ( SNDCTL_DSP_SETFRAGMENT, 0x7FFF000A ) ;
+
+    stereo = ioctl ( SOUND_PCM_WRITE_CHANNELS, _stereo ? 2 : 1 ) >= 2 ; 
+    bps    = ioctl ( SOUND_PCM_WRITE_BITS, _bps ) ; 
+    rate   = ioctl ( SOUND_PCM_WRITE_RATE, _rate ) ; 
+
+    getBufferInfo () ;
+    init_bytes = buff_info.bytes ;
+  }
+}
+
+
+void slDSP::close ()
+{
+  if ( fd >= 0 )
+    ::close ( fd ) ;
+}
+
+
+int slDSP::getDriverBufferSize ()
+{
+  if ( error )
+    return 0 ;
+
+  getBufferInfo () ;
+  return buff_info.fragsize ;
+}
+
+void slDSP::getBufferInfo ()
+{
+  if ( error )
+    return ;
+
+  if ( ::ioctl ( fd, SNDCTL_DSP_GETOSPACE, & buff_info ) < 0 )
+  {
+    perror ( "slDSP: getBufferInfo" ) ;
+    error = SL_TRUE ;
+    return ;
+  }
+}
+
+
+void slDSP::write ( void *buffer, size_t length )
+{
+  if ( error || length <= 0 )
+    return ;
+
+  int nwritten = ::write ( fd, (const char *) buffer, length ) ;
+
+  if ( nwritten < 0 )
+    perror ( "slDSP: write" ) ;
+  else
+  if ( nwritten != length )
+    perror ( "slDSP: short write" ) ;
+}
+
+
+float slDSP::secondsRemaining ()
+{
+  if ( error )
+    return 0.0f ;
+
+  getBufferInfo () ;
+
+  int samples_left = buff_info.fragments * buff_info.fragsize ;
+
+  if (   stereo  ) samples_left /= 2 ;
+  if ( bps == 16 ) samples_left /= 2 ;
+  return   (float) samples_left / (float) rate ;
+}
+
+
+float slDSP::secondsUsed ()
+{
+  if ( error )
+    return 0.0f ;
+
+  getBufferInfo () ;
+
+  int samples_used = init_bytes - buff_info.bytes ;
+
+  if (  stereo   ) samples_used /= 2 ;
+  if ( bps == 16 ) samples_used /= 2 ;
+  return   (float) samples_used / (float) rate ;
+}
+
+
+void slDSP::sync ()
+{ 
+   if ( !error) ::ioctl ( fd, SOUND_PCM_SYNC , 0 ) ; 
+}
+
+void slDSP::stop ()
+{ 
+   if ( !error) ::ioctl ( fd, SOUND_PCM_RESET, 0 ) ; 
+}
+
+#endif
+
+#ifdef WIN32
+
+/* ------------------------------------------------------------ */
+/* win32                                                        */
+/* ------------------------------------------------------------ */
+
+static void    wperror(MMRESULT num)
+{
+   char        buffer[0xff];  // yes, this is hardcoded :-)
+
+   waveOutGetErrorText( num, buffer, sizeof(buffer)-1);
+
+   fprintf( stderr, "SlDSP: %s\n", buffer );
+   fflush ( stderr );
+}
+
+
+
+void CALLBACK waveOutProc( HWAVEOUT hwo, UINT uMsg,    
+      DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
+{   
+   switch( uMsg )
+   {
+   case    WOM_CLOSE:
+      break;
+
+   case    WOM_OPEN:
+      break;
+
+   case    WOM_DONE:
+      waveOutUnprepareHeader( (HWAVEOUT)dwParam1, 
+         (LPWAVEHDR)dwParam2, sizeof( WAVEHDR ));
+      break;
+   }
+}
+
+
+void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
+{
+   MMRESULT    result;
+
+   hWaveOut    = NULL;
+   curr_header = 0;
+   counter     = 0;
+
+   Format.wFormatTag       = WAVE_FORMAT_PCM;          
+   Format.nChannels        = _stereo ? 2 : 1;
+   Format.nSamplesPerSec   = _rate;
+   Format.wBitsPerSample   = _bps;
+   Format.nBlockAlign      = 1;
+   Format.nAvgBytesPerSec  = _rate * Format.nChannels;
+   Format.cbSize           = 0;
+
+   result = waveOutOpen( & hWaveOut, WAVE_MAPPER, & Format, NULL, 
+      0L, WAVE_FORMAT_QUERY );
+
+   if ( result != MMSYSERR_NOERROR )
+   {
+      wperror( result);
+
+      error      = SL_TRUE  ;
+      stereo     = SL_FALSE ;
+      bps        = _bps     ;
+      rate       = _rate    ;
+      init_bytes =    0     ;
+      
+      return;
+   }
+
+   // Now the hwaveouthandle "should" be valid 
+
+   if ( ( result = waveOutOpen( & hWaveOut, WAVE_MAPPER, 
+         (WAVEFORMATEX *)& Format, (DWORD)waveOutProc, 
+         0L, CALLBACK_FUNCTION )) != MMSYSERR_NOERROR )
+   {
+      wperror( result);
+
+      error      = SL_TRUE ;
+      stereo     = SL_FALSE ;
+      bps        = _bps     ;
+      rate       = _rate    ;
+      init_bytes =    0     ;
+      return;
+   }
+   else
+   {
+      error  = SL_FALSE ;
+      stereo = _stereo;
+      bps    = _bps;
+      rate   = _rate;
+
+      /* hmm ?! */ 
+
+      init_bytes = 1024*8;
+   }
+}
+
+
+void slDSP::close ()
+{
+   if ( hWaveOut != NULL )
+   {
+      waveOutClose( hWaveOut );
+      hWaveOut = NULL;
+   }
+}
+
+int slDSP::getDriverBufferSize ()
+{
+   if ( error )
+      return 0 ;
+
+   /* hmm ?! */
+
+   return    1024*8;
+}
+
+void slDSP::getBufferInfo ()
+{
+    return ;
+}
+
+
+void slDSP::write ( void *buffer, size_t length )
+{
+   MMRESULT    result;
+
+   if ( error || length <= 0 )
+      return ;
+
+   wavehdr[curr_header].lpData          = (LPSTR) buffer;
+   wavehdr[curr_header].dwBufferLength  = (long) length;
+   wavehdr[curr_header].dwBytesRecorded = 0L;
+   wavehdr[curr_header].dwUser          = NULL;
+   wavehdr[curr_header].dwFlags         = 0;
+   wavehdr[curr_header].dwLoops         = 0;
+   wavehdr[curr_header].lpNext          = NULL;
+   wavehdr[curr_header].reserved        = 0;
+
+
+   result = waveOutPrepareHeader( hWaveOut, & wavehdr[curr_header], 
+      sizeof(WAVEHDR));
+
+   if ( result != MMSYSERR_NOERROR ) 
+   {
+      wperror ( result );
+      error = SL_TRUE;
+   }
+
+   result = waveOutWrite(hWaveOut, & wavehdr[curr_header], 
+      sizeof(WAVEHDR));
+   if ( result != MMSYSERR_NOERROR )
+   {
+      wperror ( result );
+      error = SL_TRUE;
+   }
+   
+   counter ++; 
+   
+   curr_header = ( curr_header + 1 ) % 3;
+}
+
+
+float slDSP::secondsRemaining ()
+{
+   if ( error )
+      return 0.0f ;
+   
+   return 0.0f ;
+}
+
+
+float slDSP::secondsUsed ()
+{
+   int      samples_used;
+   MMRESULT    result;
+   float    samp_time;
+
+   if ( error )
+      return 0.0f ;
+
+   mmt.wType = TIME_BYTES;
+
+   result = waveOutGetPosition( hWaveOut, &mmt, sizeof( mmt ));
+
+   if ( mmt.u.cb == 0 || counter == 0)
+      return    (float)0.0;
+
+   samples_used = ( init_bytes * counter ) - mmt.u.cb;
+
+   if (  stereo   ) samples_used /= 2 ;
+   if ( bps == 16 ) samples_used /= 2 ;
+
+   samp_time  = (float) samples_used / (float) rate ;
+
+   //printf("%0.2f position=%ld total written=%ld\n", 
+   // samp_time, mmt.u.cb, init_bytes * counter );
+   
+   return   samp_time;
+}
+
+
+void slDSP::sync ()
+{
+}
+
+void slDSP::stop ()
+{
+   waveOutReset( hWaveOut );
+}
+
+/* ------------------------------------------------------------ */
+/* OpenBSD 2.3 this should be very close to SUN Audio           */
+/* ------------------------------------------------------------ */
+
+#elif defined(__OpenBSD__)
+void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
+{
+
+  counter = 0;
+  
+  fd = ::open ( device, O_RDWR ) ;
+    
+  if ( fd < 0 )
+  {
+    perror ( "slDSP: open" ) ;
+    error = SL_TRUE ;
+  }
+  else
+  {    
+  
+    if( ::ioctl( fd, AUDIO_GETINFO, &ainfo) == -1)
+    {
+      perror("slDSP: open - getinfo");
+      stereo     = SL_FALSE ;
+      bps        =    8     ;
+      rate       =  8000    ;
+      init_bytes =    0     ;
+      
+      return;
+    }
+      
+    ainfo.play.sample_rate  = _rate;
+    ainfo.play.precision    = _bps;    
+    ainfo.play.channels     = _stereo ? 2 : 1;
+    
+    ainfo.play.encoding     = AUDIO_ENCODING_ULINEAR;
+
+    if( :: ioctl(fd, AUDIO_SETINFO, &ainfo) == -1)
+    {
+      perror("slDSP: open - setinfo");
+      stereo     = SL_FALSE ;
+      bps        =    8     ;
+      rate       =  8000    ;
+      init_bytes =    0     ;
+      return;
+    }
+
+    rate    = _rate;
+    stereo  = _stereo;
+    bps     = _bps;
+
+    error = SL_FALSE ;
+
+    getBufferInfo ();
+    
+    // I could not change the size, 
+    // so let's try this ...
+    
+    init_bytes = 1024 * 8;
+  }
+}
+
+
+void slDSP::close ()
+{
+  if ( fd >= 0 )
+    ::close ( fd ) ;
+}
+
+
+int slDSP::getDriverBufferSize ()
+{
+  if ( error )
+    return 0 ;
+
+  getBufferInfo () ;
+  
+  // HW buffer is 0xffff on my box
+  //return ainfo.play.buffer_size;
+  
+  return  1024 * 8;
+}
+
+void slDSP::getBufferInfo ()
+{
+  if ( error )
+    return ;
+
+  if( ::ioctl( fd, AUDIO_GETINFO, &ainfo) < 0)
+  {
+    perror ( "slDSP: getBufferInfo" ) ;
+    error = SL_TRUE ;
+    return ;
+  }
+    
+  if( ::ioctl( fd, AUDIO_GETOOFFS, &audio_offset ) < 0)
+  {
+    perror ( "slDSP: getBufferInfo" ) ;
+    error = SL_TRUE ;
+    return ;
+  }
+}
+
+
+void slDSP::write ( void *buffer, size_t length )
+{
+  if ( error || length <= 0 )
+    return ;
+  
+  int nwritten = ::write ( fd, (const char *) buffer, length ) ;
+
+  if ( nwritten < 0 )
+    perror ( "slDSP: write" ) ;
+  else if ( nwritten != length )
+      perror ( "slDSP: short write" ) ;
+      
+  counter ++; /* hmmm */
+}
+
+
+float slDSP::secondsRemaining ()
+{
+    return 0.0f ;
+}
+
+
+float slDSP::secondsUsed ()
+{
+  /*
+   * original formula from Steve:
+   * -----------------------------
+   *
+   * int samples_used = init_bytes - buff_info.bytes ;
+   *                    |            |
+   *                    |            +--- current available
+   *                    |                 space in bytes !
+   *                    +---------------- available space
+   *                                      when empty;
+   * 
+   * sample_used contains the number of bytes which are
+   * "used" or in the DSP "pipeline".
+   */
+
+
+  int samples_used;
+  
+  if ( error )
+    return 0.0f ;
+
+  getBufferInfo () ;
+
+  //This is wrong: this is the hw queue in the kernel !
+  //samples_used   = ainfo.play.buffer_size - audio_offset.offset ;
+
+  // This is: all data written minus where we are now in the queue
+  
+  if ( counter == 0 )
+      return 0.0;
+
+  samples_used = ( counter * init_bytes ) - audio_offset.samples;
+  
+  if (  stereo   ) samples_used /= 2 ;
+  if ( bps == 16 ) samples_used /= 2 ;
+
+  return   (float) samples_used / (float) rate ;
+}
+
+
+void slDSP::sync ()
+{ 
+   if ( !error) ::ioctl ( fd, AUDIO_FLUSH , 0 ) ; 
+}
+
+void slDSP::stop ()
+{ 
+   // nothing found yet 
+}
+
+/* ------------------------------------------------------------ */
+/* SGI IRIX audio                                               */
+/* ------------------------------------------------------------ */
+
+#elif defined(sgi)
+
+void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
+{
+  if ( _bps != 8 )
+  {
+    perror ( "slDSP: supports only 8bit audio for sgi" ) ;
+    error = SL_TRUE;
+    return;
+  }
+
+  init_bytes = 1024 * 8;
+
+  config  = ALnewconfig();
+  
+  ALsetchannels (  config, _stereo ? AL_STEREO : AL_MONO );
+  ALsetwidth    (  config, _bps == 8 ? AL_SAMPLE_8 : AL_SAMPLE_16 );
+  ALsetqueuesize(  config, init_bytes );
+
+  port = ALopenport( device, "w", config );
+    
+  if ( port == NULL )
+  {
+    perror ( "slDSP: open" ) ;
+    error = SL_TRUE ;
+  }
+  else
+  {    
+    long params[2] = {AL_OUTPUT_RATE, 0 };
+
+    params[1] = _rate;
+
+    if ( ALsetparams(AL_DEFAULT_DEVICE, params, 2) != 0 )
+       {
+       perror ( "slDSP: open - ALsetparams" ) ;
+       error = SL_TRUE ;
+       return;
+       }
+  
+    rate    = _rate;
+    stereo  = _stereo;
+    bps     = _bps;
+
+    error = SL_FALSE ;
+
+  }
+}
+
+
+void slDSP::close ()
+{
+  if ( port != NULL )
+  {
+     ALcloseport ( port   );
+     ALfreeconfig( config );
+     port = NULL;
+  }
+}
+
+
+int slDSP::getDriverBufferSize ()
+{
+  if ( error )
+    return 0 ;
+
+  return  ALgetqueuesize( config );
+}
+
+void slDSP::getBufferInfo ()
+{
+  if ( error )
+    return ;
+}
+
+
+void slDSP::write ( void *buffer, size_t length )
+{
+  char *buf = (char *)buffer;
+  int  i;
+
+  if ( error || length <= 0 )
+    return ;
+
+  // Steve: is this a problem ??
+
+  for ( i = 0; i < length; i ++ )
+    buf[i] = buf[i] >> 1;
+
+  ALwritesamps(port, (void *)buf, length );
+}
+
+
+float slDSP::secondsRemaining ()
+{
+  int   samples_remain;
+
+  if ( error )
+    return 0.0f ;
+
+  samples_remain = ALgetfillable(port);
+
+  if (  stereo   ) samples_remain /= 2 ;
+  if ( bps == 16 ) samples_remain /= 2 ;
+
+  return   (float) samples_remain / (float) rate ;
+}
+
+
+float slDSP::secondsUsed ()
+{
+  int   samples_used;
+  
+  if ( error )
+    return 0.0f ;
+
+  samples_used = ALgetfilled(port);
+
+  if (  stereo   ) samples_used /= 2 ;
+  if ( bps == 16 ) samples_used /= 2 ;
+
+  return   (float) samples_used / (float) rate ;
+}
+
+
+void slDSP::sync ()
+{ 
+  /* found this in the header file - but no description
+   * or example for the long parameter.
+   */
+
+  // ALflush(ALport, long);
+}
+
+void slDSP::stop ()
+{ 
+}
+
+
+#endif
+
diff --git a/src/slEnvelope.cxx b/src/slEnvelope.cxx
new file mode 100644 (file)
index 0000000..74cc52b
--- /dev/null
@@ -0,0 +1,92 @@
+
+#include "sl.h"
+
+float slEnvelope::getValue ( float _time )
+{
+  float delta ;
+  int   step = getStepDelta ( &_time, &delta ) ;
+
+  return delta * (_time - time[step]) + value[step] ;
+}
+
+
+
+int slEnvelope::getStepDelta ( float *_time, float *delta )
+{
+  float tt ;
+
+  if ( replay_mode == SL_SAMPLE_LOOP )
+  {
+    tt = floor ( *_time / time [ nsteps-1 ] ) ; 
+    *_time -= tt * time [ nsteps-1 ] ;
+  }
+
+  tt = *_time ;
+
+  if ( tt <= time[    0   ] ) { *delta = 0.0f ; return 0 ; }
+  if ( tt >= time[nsteps-1] ) { *delta = 0.0f ; return nsteps-1 ; }
+
+  for ( int i = 1 ; i <= nsteps-1 ; i++ )
+    if ( tt <= time[i] )
+    {
+      float t1 = time[i-1] ; float v1 = value[i-1] ;
+      float t2 = time[ i ] ; float v2 = value[ i ] ;
+
+      if ( t1 == t2 )
+      {
+        *delta = 0.0f ;
+       return i ;
+      }
+
+      *delta = (v2-v1) / (t2-t1) ;
+      return i-1 ;
+    }
+
+  *delta = 0.0f ;
+  return nsteps - 1 ;
+}
+
+void slEnvelope::applyToVolume ( Uchar *dst, Uchar *src,
+                                 int nframes, int start )
+{
+  float  delta ;
+  float  _time = slScheduler::getCurrent() -> getElapsedTime ( start ) ;
+  int     step = getStepDelta ( &_time, &delta ) ;
+  float _value = delta * (_time - time[step]) + value[step] ;
+
+  delta /= (float) slScheduler::getCurrent() -> getRate () ;
+
+  while ( nframes-- )
+  {
+    register int res = (int)( (float)((int)*(src++)-0x80) * _value ) + 0x80 ;
+
+    _value += delta ;
+
+    *(dst++) = ( res > 255 ) ? 255 : ( res < 0 ) ? 0 : res ;
+  }
+}
+
+void slEnvelope::applyToInvVolume ( Uchar *dst, Uchar *src,
+                                    int nframes, int start )
+{
+  float  delta ;
+  float  _time = slScheduler::getCurrent() -> getElapsedTime ( start ) ;
+  int     step = getStepDelta ( &_time, &delta ) ;
+  float _value = delta * (_time - time[step]) + value[step] ;
+
+  delta /= (float) slScheduler::getCurrent() -> getRate () ;
+
+  delta = - delta ;
+  _value = 1.0 - _value ;
+
+  while ( nframes-- )
+  {
+    register int res = (int)( (float)((int)*(src++)-0x80) * _value ) + 0x80 ;
+
+    _value += delta ;
+
+    *(dst++) = ( res > 255 ) ? 255 : ( res < 0 ) ? 0 : res ;
+  }
+}
+
+
diff --git a/src/slPortability.h b/src/slPortability.h
new file mode 100644 (file)
index 0000000..09953a5
--- /dev/null
@@ -0,0 +1,72 @@
+
+#ifndef __SLPORTABILITY_H__
+#define __SLPORTABILITY_H__ 1
+
+/* ------------------------------------------------------------- */
+/* OS specific includes and defines ...                          */
+/* ------------------------------------------------------------- */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+#undef VERSION
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef  WIN32
+#include <unistd.h>
+#include <sys/ioctl.h>
+#else
+#include <windows.h>
+#ifdef __CYGWIN32__
+#  define NEAR /* */
+#  define FAR  /* */
+#  define WHERE_EVER_YOU_ARE /* Curt: optional, but it reminds me of a song */
+#endif
+#include <mmsystem.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef __linux__
+#define SL_USING_OSS_AUDIO 1
+#endif
+
+#ifdef SL_USING_OSS_AUDIO
+#if defined(__linux__)
+#include <linux/soundcard.h>
+#elif defined(__FreeBSD__)
+#include <machine/soundcard.h>
+#else
+/*
+  Tom thinks this file may be <sys/soundcard.h> under some
+  unixen - but that isn't where the OSS manuals say it
+  should be.
+
+  If you ever find out the truth, please email me:
+     Steve Baker <sjbaker1@airmail.net>
+*/
+#include <soundcard.h>
+#endif
+#endif
+
+#ifdef __OpenBSD__
+#include <sys/audioio.h>
+#endif
+
+#ifdef WIN32
+#define strcasecmp stricmp   /* Yes, Steve really does *HATE* Windoze */
+#endif
+
+/* Tom */
+
+#ifdef sgi
+#include <audio.h>
+#endif
+
+#endif
+
diff --git a/src/slSample.cxx b/src/slSample.cxx
new file mode 100644 (file)
index 0000000..14c6b53
--- /dev/null
@@ -0,0 +1,505 @@
+
+
+#include "sl.h"
+#include <math.h>
+
+void slSample::autoMatch ( slDSP *dsp )
+{
+  if ( dsp == NULL ) return ;
+
+  changeRate   ( dsp->getRate   () ) ;
+  changeBps    ( dsp->getBps    () ) ;
+  changeStereo ( dsp->getStereo () ) ;
+}
+
+void slSample::adjustVolume ( float vol )
+{
+  for ( int i = 0 ; i < length ; i++ )
+  {
+    int s = (int)(((float) buffer[i] - (float) 0x80) * vol) + 0x80 ;
+
+    buffer [ i ] = ( s > 255 ) ? 255 :
+                     ( s < 0 ) ? 0 : s ;
+  }
+}
+
+
+void slSample::changeRate   ( int r )
+{
+  if ( r == rate ) return ;
+
+  int    length1 = length / (getBps ()/8) ;
+  int    length2 = (int) ( (float) length1 * ( (float) r / (float) rate ) ) ;
+  Uchar *buffer2 = new Uchar [ length2 ] ;
+
+  float step = (float) length1 / (float) length2 ;
+
+  for ( int i = 0 ; i < length2 / (getBps()/8); i++ )
+  {
+    float pos = (float) i * step ;
+
+    int p1 = (int) floor ( pos ) ;
+    int p2 = (int) ceil  ( pos ) ;
+
+    if ( stereo )
+    {
+      if ( ( p1 & 1 ) != ( i & 1 ) ) { pos++ ; p1++ ; p2++ ; }
+      p2++ ;
+    }
+
+    float ratio = pos - (float) p1 ;
+
+    float b1 = (getBps()==8) ?
+        (float)           buffer [(p1<0)?0:(p1>=length1)?length1-1:p1] :
+        (float) ((Ushort*)buffer)[(p1<0)?0:(p1>=length1)?length1-1:p1] ;
+    float b2 = (getBps()==8) ?
+        (float)           buffer [(p2<0)?0:(p2>=length1)?length1-1:p2] :
+        (float) ((Ushort*)buffer)[(p2<0)?0:(p2>=length1)?length1-1:p2] ;
+
+    float res = b1 * (1.0-ratio) + b2 * ratio ;
+
+    if ( getBps () == 8 )
+      buffer2 [ i ] = (Uchar) ( (res < 0) ? 0 : (res > 255) ? 255 : res ) ;
+    else
+      ((Ushort *) buffer2 ) [ i ] = 
+                (Ushort) ( (res < 0) ? 0 : (res > 65535) ? 65535 : res ) ;
+  }
+
+  rate   = r ;
+  length = length2 ;
+  delete buffer ;
+  buffer = buffer2 ;
+}
+
+#ifdef 0
+void slSample::changeToUnsigned ()
+{
+  if ( getBps() == 16 )
+  {
+    int length2 = length / 2 ;
+    Ushort *buffer2 = (Ushort *) buffer ;
+
+    for ( int i = 0 ; i < length2 ; i++ )
+      buffer2 [ i ] = buffer2 [ i ] + 32768 ;
+  }
+  else
+  {
+    for ( int i = 0 ; i < length ; i++ )
+      buffer [ i ] = (buffer [ i ]>0x80) ? (buffer[i]-0x80) :
+                                           (0xFF-buffer[i]) ;
+  }
+}
+#endif
+
+
+void slSample::changeBps    ( int b )
+{
+  if ( b == getBps () ) return ;
+
+  if ( b == 8 && getBps() == 16 )
+  {
+    length /= 2 ;
+    Uchar *buffer2 = new Uchar [ length ] ;
+
+    for ( int i = 0 ; i < length ; i++ )
+      buffer2 [ i ] = ((Ushort *)buffer) [ i ] >> 8 ;
+
+    delete buffer ;
+    buffer = buffer2 ;
+    setBps ( b ) ;
+  }
+  else
+  if ( b == 16 && getBps() == 8 )
+  {
+    Ushort *buffer2 = new Ushort [ length ] ;
+
+    for ( int i = 0 ; i < length ; i++ )
+      buffer2 [ i ] = buffer [ i ] << 8 ;
+
+    delete buffer ;
+    buffer = (Uchar *) buffer2 ;
+    length *= 2 ;
+    setBps ( b ) ;
+  }
+}
+
+void slSample::changeStereo ( int s )
+{
+  if ( s == getStereo () )
+    return ;
+
+  if ( s && ! getStereo () )
+  {
+    if ( getBps () == 8 )
+    {
+       Uchar *buffer2 = new Uchar [ length * 2 ] ;
+
+       for ( int i = 0 ; i < length ; i++ )
+         buffer2 [ i*2 ] = buffer2 [ i*2+1 ] = buffer [ i ] ;
+
+       delete buffer ;
+       buffer = buffer2 ;
+       length *= 2 ;
+       setStereo ( SL_TRUE ) ;
+    }
+    else
+    {
+       Ushort *buffer2 = new Ushort [ length ] ;
+
+       for ( int i = 0 ; i < length / 2 ; i++ )
+         buffer2 [ i*2 ] = buffer2 [ i*2+1 ] = ((Ushort *) buffer) [ i ] ;
+
+       delete buffer ;
+       buffer = (Uchar *)buffer2 ;
+       length *= 2 ;
+       setStereo ( SL_TRUE ) ;
+    }
+  }
+  else
+  {
+    if ( getBps () == 8 )
+    {
+       Uchar *buffer2 = new Uchar [ length / 2 ] ;
+
+       for ( int i = 0 ; i < length ; i++ )
+         buffer2 [ i ] = ((int)buffer [ i*2 ] + (int)buffer [ i*2 + 1 ] ) / 2 ;
+
+       delete buffer ;
+       buffer = buffer2 ;
+       length /= 2 ;
+       setStereo ( SL_FALSE ) ;
+    }
+    else
+    {
+       Ushort *buffer2 = new Ushort [ length / 4 ] ;
+
+       for ( int i = 0 ; i < length / 4 ; i++ )
+         buffer2 [ i ] = ((int)((Ushort *)buffer) [ i*2 ] +
+                          (int)((Ushort *)buffer) [ i*2 + 1 ] ) / 2 ;
+
+       delete buffer ;
+       buffer = (Uchar *)buffer2 ;
+       length /= 2 ;
+       setStereo ( SL_FALSE ) ;
+    }
+  }
+}
+
+
+static void swap_Ushort ( Ushort *i )
+{
+  *i = ((*i << 8) & 0xFF00) +
+       ((*i >> 8) & 0x00FF) ;
+}
+
+static void swap_int ( int *i )
+{
+  *i = ((*i << 24) & 0xFF000000) +
+       ((*i <<  8) & 0x00FF0000) +
+       ((*i >>  8) & 0x0000FF00) +
+       ((*i >> 24) & 0x000000FF) ;
+}
+
+int slSample::loadFile ( char *fname )
+{
+  if ( strcasecmp ( & fname [ strlen ( fname ) - 4 ], ".wav" ) == 0 )
+    return loadWavFile ( fname ) ;
+
+  if ( strcasecmp ( & fname [ strlen ( fname ) - 3 ], ".au" ) == 0 )
+    return loadAUFile ( fname ) ;
+
+  if ( strcasecmp ( & fname [ strlen ( fname ) - 3 ], ".ub" ) == 0 )
+    return loadRawFile ( fname ) ;
+
+  fprintf ( stderr, "slSample:loadFile: Unknown file type for '%s'.\n",
+                                    fname ) ;
+  return SL_FALSE ;
+}
+
+
+int slSample::loadWavFile ( char *fname )
+{
+  int found_header   = SL_FALSE ;
+  int needs_swabbing = SL_FALSE ;
+
+  delete buffer ;
+  buffer = NULL ;
+  length = 0 ;
+
+  FILE *fd = fopen ( fname, "rb" ) ;
+
+  if ( fd == NULL )
+  {
+    fprintf ( stderr,
+            "slSample: loadWavFile: Cannot open '%s' for reading.\n",
+            fname ) ;
+    return SL_FALSE ;
+  }
+
+  char magic [ 8 ] ;
+
+  if ( fread ( magic, 4, 1, fd ) == -1 ||
+       magic[0] != 'R' || magic[1] != 'I' ||
+       magic[2] != 'F' || magic[3] != 'F' )
+  {
+    fprintf ( stderr, "slWavSample: File '%s' has wrong magic number\n", fname ) ;
+    fprintf ( stderr, "            - it probably isn't in '.wav' format.\n" ) ;
+    fclose ( fd ) ;
+    return SL_FALSE ;
+  }
+
+  int leng1 ;
+
+  if ( fread ( & leng1, sizeof(int), 1, fd ) == -1 )
+  {
+    fprintf ( stderr, "slSample: File '%s' has premature EOF in header\n", fname ) ;
+    fclose ( fd ) ;
+    return SL_FALSE ;
+  }
+
+  fread ( magic, 4, 1, fd ) ;
+
+  if ( magic[0] != 'W' || magic[1] != 'A' ||
+       magic[2] != 'V' || magic[3] != 'E' )
+  {
+    fprintf ( stderr, "slSample: File '%s' has no WAVE tag.\n", fname ) ;
+    fclose ( fd ) ;
+    return SL_FALSE ;
+  }
+
+  while ( ! feof ( fd ) )
+  {
+    fread ( magic, 4, 1, fd ) ;
+
+    if ( magic[0] == 'f' && magic[1] == 'm' &&
+        magic[2] == 't' && magic[3] == ' ' )
+    {
+      found_header = SL_TRUE ;
+
+      if ( fread ( & leng1, sizeof(int), 1, fd ) == -1 )
+      {
+       fprintf ( stderr, "slSample: File '%s' has premature EOF in header\n", fname ) ;
+       fclose ( fd ) ;
+       return SL_FALSE ;
+      }
+
+      if ( leng1 > 65536 )
+      {
+       needs_swabbing = SL_TRUE ;
+       swap_int ( & leng1 ) ;
+      }
+
+      Ushort header [ 8 ] ;
+
+      if ( leng1 != sizeof ( header ) )
+       fprintf ( stderr,
+               "slSample: File '%s' has unexpectedly long (%d byte) header\n",
+               fname, leng1 ) ;
+
+      fread ( & header, sizeof(header), 1, fd ) ;
+
+      for ( int junk = sizeof(header) ; junk < leng1 ; junk++ )
+        fgetc ( fd ) ;
+
+      if ( needs_swabbing )
+      {
+       swap_Ushort ( & header[0] ) ;
+       swap_Ushort ( & header[1] ) ;
+       swap_int    ( (int *) & header[2] ) ;
+       swap_int    ( (int *) & header[4] ) ;
+       swap_Ushort ( & header[6] ) ;
+       swap_Ushort ( & header[7] ) ;
+      }
+
+      if ( header [ 0 ] != 0x0001 )
+      {
+       fprintf ( stderr, "slSample: File '%s' is not WAVE_FORMAT_PCM!\n", fname ) ;
+       fclose ( fd ) ;
+       return SL_FALSE ;
+      }
+
+      setStereo ( header[1] > 1 ) ;
+      setRate   ( *((int *) (& header[2])) ) ;
+      setBps    ( header[7] ) ;
+    }
+    else
+    if ( magic[0] == 'd' && magic[1] == 'a' &&
+        magic[2] == 't' && magic[3] == 'a' )
+    {
+      if ( ! found_header )
+      {
+       fprintf ( stderr, "slSample: File '%s' has no data section\n", fname ) ;
+       fclose ( fd ) ;
+       return SL_FALSE ;
+      }
+
+      if ( fread ( & length, sizeof(int), 1, fd ) == -1 )
+      {
+       fprintf ( stderr, "slSample: File '%s' has premature EOF in data\n", fname ) ;
+       fclose ( fd ) ;
+       return SL_FALSE ;
+      }
+
+      if ( needs_swabbing )
+       swap_int ( & length ) ;
+
+      buffer = new Uchar [ length ] ;
+
+      fread ( buffer, 1, length, fd ) ;
+
+      if ( getBps () == 16 )
+      {
+        Ushort *b = (Ushort*) buffer ;
+
+        for ( int i = 0 ; i < length/2 ; i++ )
+          b [ i ] = (Ushort) ( (int)((short) b [ i ]) + 32768 ) ;
+      }
+
+      fclose ( fd ) ;
+      return SL_TRUE ;
+    }
+  }
+
+  fclose ( fd ) ;
+  return SL_FALSE ;
+}
+
+int slSample::loadAUFile ( char *fname )
+{
+  delete buffer ;
+  buffer = NULL ;
+  length = 0 ;
+
+  FILE *fd = fopen ( fname, "rb" ) ;
+
+  if ( fd == NULL )
+  {
+    fprintf ( stderr,
+            "slSample: loadAUFile: Cannot open '%s' for reading.\n",
+            fname ) ;
+    return SL_FALSE ;
+  }
+
+  char magic [ 4 ] ;
+
+  if ( fread ( magic, 4, 1, fd ) == -1 ||
+       magic[0] != '.' || magic[1] != 's' ||
+       magic[2] != 'n' || magic[3] != 'd' )
+  {
+    fprintf ( stderr, "slSample: File '%s' has wrong magic number\n", fname ) ;
+    fprintf ( stderr, "            - it probably isn't in '.au' format.\n" ) ;
+    fclose ( fd ) ;
+    return SL_FALSE ;
+  }
+
+  int hdr_length ;
+  int dat_length ;
+  int nbytes ;
+  int irate  ;
+  int nchans ;
+
+  if ( fread ( & hdr_length, sizeof(int), 1, fd ) == -1 ||
+       fread ( & dat_length, sizeof(int), 1, fd ) == -1 ||
+       fread ( & nbytes    , sizeof(int), 1, fd ) == -1 ||
+       fread ( & irate     , sizeof(int), 1, fd ) == -1 ||
+       fread ( & nchans    , sizeof(int), 1, fd ) == -1 )
+  {
+    fprintf ( stderr, "slSample: File '%s' has premature EOF in header\n", fname ) ;
+    fclose ( fd ) ;
+    return SL_FALSE ;
+  }
+
+  if ( hdr_length > 65536 )
+  {
+    swap_int ( & hdr_length ) ;
+    swap_int ( & dat_length ) ;
+    swap_int ( & nbytes ) ;
+    swap_int ( & irate  ) ;
+    swap_int ( & nchans ) ;
+  }
+
+  bps    = nbytes * 8 ;
+  stereo = (nchans>1) ;
+  rate   = irate      ;
+
+  if ( nbytes > 2 || nbytes <= 0 || hdr_length > 512 || hdr_length < 24 ||
+       irate > 65526 || irate <= 1000 || nchans < 1 || nchans > 2 )
+  {
+    fprintf ( stderr, "slSample: File '%s' has a very strange header\n", fname ) ;
+
+    fprintf ( stderr, "  Header Length = %d\n", hdr_length ) ;
+    fprintf ( stderr, "  Data   Length = %d\n", dat_length ) ;
+    fprintf ( stderr, "  Bytes/sample  = %d\n", nbytes     ) ;
+    fprintf ( stderr, "  Sampling Rate = %dHz\n",irate     ) ;
+    fprintf ( stderr, "  Num Channels  = %d\n", nchans     ) ;
+    fprintf ( stderr, "\n" ) ;
+    fclose ( fd ) ;
+    return SL_FALSE ;
+  }
+
+  if ( hdr_length > 24 )
+  {
+    delete comment ;
+    comment = new char [ hdr_length - 24 + 1 ] ;
+
+    fread ( comment, 1, hdr_length - 24, fd ) ;
+  }
+
+  if ( dat_length > 0 )
+  {
+    buffer = new Uchar [ dat_length ] ;
+    length = fread ( buffer, 1, dat_length, fd ) ;
+
+    if ( length != dat_length )
+      fprintf ( stderr, "slAUSample: File '%s' has premature EOF in data.\n", fname ) ;
+  }
+
+  fclose ( fd ) ;
+  return SL_TRUE ;
+}
+
+
+int slSample::loadRawFile ( char *fname )
+{
+  delete buffer ;
+  buffer = NULL ;
+  length = 0 ;
+
+  FILE *fd = fopen ( fname, "rb" ) ;
+
+  if ( fd == NULL )
+  {
+    fprintf ( stderr,
+              "slSample: loadRawFile: Cannot open '%s' for reading.\n",
+             fname ) ;
+    return SL_FALSE ;
+  }
+
+  struct stat stat_buf ;
+
+  if ( fstat ( fileno ( fd ), & stat_buf ) != 0 )
+  {
+    fprintf ( stderr,
+             "slSample: loadRawFile: Cannot get status for '%s'.\n",
+             fname ) ;        
+    fclose ( fd ) ;
+    return SL_FALSE ;
+  }
+
+  length = stat_buf . st_size ;
+
+  if ( length > 0 )
+  {
+    buffer = new Uchar [ length ] ;
+    length = fread ( buffer, 1, length, fd ) ;
+  }
+
+  bps    = 8     ;
+  stereo = SL_FALSE ;
+  rate   = 8000  ;  /* Guess */
+
+  fclose ( fd ) ;
+  return SL_TRUE ;
+}
+
+
diff --git a/src/slSamplePlayer.cxx b/src/slSamplePlayer.cxx
new file mode 100644 (file)
index 0000000..fa079f4
--- /dev/null
@@ -0,0 +1,150 @@
+
+#include "sl.h"
+
+void slSamplePlayer::addEnvelope ( int i, slEnvelope *_env, slEnvelopeType _type )
+{
+  if ( i < 0 || i >= SL_MAX_ENVELOPES ) return ;
+
+  if ( env [ i ] != NULL )
+    env [ i ] -> unRef () ;
+
+  env [ i ] = _env ;
+
+  if ( _env != NULL )
+    env [ i ] -> ref () ;
+
+  env_type [ i ] = _type ;
+  env_start_time [ i ] = slScheduler::getCurrent() -> getTimeNow () ;
+}
+
+int slSamplePlayer::preempt ( int delay )
+{
+  slScheduler::getCurrent() -> addCallBack ( callback, sample, SL_EVENT_PREEMPTED, magic ) ;
+
+  switch ( preempt_mode )
+  {
+    case SL_SAMPLE_CONTINUE: if ( isRunning() )
+                              return SL_FALSE ;
+                            /* FALLTHROUGH! */
+    case SL_SAMPLE_DELAY   :                   break ;
+    case SL_SAMPLE_MUTE    : skip  ( delay ) ; break ;
+    case SL_SAMPLE_ABORT   : stop  ()        ; break ;
+    case SL_SAMPLE_RESTART : reset ()        ; break ;
+  }
+
+  return SL_TRUE ;
+}
+
+slSamplePlayer::~slSamplePlayer ()
+{
+  if ( sample )
+    sample -> unRef () ;
+
+  slScheduler::getCurrent() -> addCallBack ( callback, sample, SL_EVENT_COMPLETE, magic ) ;
+}
+
+void slSamplePlayer::skip ( int nframes )
+{
+  if ( nframes < lengthRemaining )
+  {
+    lengthRemaining -= nframes ;
+    bufferPos       += nframes ;
+  }
+  else 
+  if ( replay_mode == SL_SAMPLE_LOOP )
+  {
+    slScheduler::getCurrent() -> addCallBack ( callback, sample, SL_EVENT_LOOPED, magic ) ;
+
+    nframes -= lengthRemaining ;
+
+    while ( nframes >= sample->getLength () )
+      nframes -= sample->getLength () ;
+
+    lengthRemaining = sample->getLength() - nframes ;
+    bufferPos = & ( sample->getBuffer() [ nframes ] ) ;
+  }
+  else
+    stop () ;
+}
+
+
+Uchar *slSamplePlayer::read ( int nframes, Uchar *spare1, Uchar *spare2 )
+{
+  if ( isWaiting() ) start () ;
+
+  if ( nframes > lengthRemaining ) /* This is an error */
+  {
+    fprintf ( stderr, "slSamplePlayer: FATAL ERROR - Mixer Requested too much data.\n" ) ;
+    abort () ;
+  }
+
+  Uchar *src = bufferPos ;
+  Uchar *dst = spare1 ;
+
+  for ( int i = 0 ; i < SL_MAX_ENVELOPES ; i++ )
+  {
+    if ( env[i] )
+    {
+      switch ( env_type [ i ] )
+      {
+        case SL_INVERSE_PITCH_ENVELOPE :
+        case SL_PITCH_ENVELOPE  :
+          memcpy ( dst, src, nframes ) /* Tricky! */ ;
+          break ;
+
+        case SL_INVERSE_VOLUME_ENVELOPE:
+          env[i]->applyToInvVolume ( dst,src,nframes,env_start_time[i] ) ;
+          break ;
+
+        case SL_VOLUME_ENVELOPE :
+          env[i]->applyToVolume ( dst,src,nframes,env_start_time[i] ) ;
+          break ;
+
+        case SL_INVERSE_FILTER_ENVELOPE:
+        case SL_FILTER_ENVELOPE :
+          memcpy ( dst, src, nframes ) /* Tricky! */ ;
+          break ;
+
+        case SL_INVERSE_PAN_ENVELOPE   :
+        case SL_PAN_ENVELOPE    :
+          memcpy ( dst, src, nframes ) /* Tricky! */ ;
+          break ;
+
+        case SL_INVERSE_ECHO_ENVELOPE  :
+        case SL_ECHO_ENVELOPE   :
+          memcpy ( dst, src, nframes ) /* Tricky! */ ;
+          break ;
+      }
+
+      if ( dst == spare1 )
+      {
+        src = spare1 ;
+        dst = spare2 ;
+      }
+      else
+      {
+        dst = spare1 ;
+        src = spare2 ;
+      }
+    }
+  }
+  if ( nframes < lengthRemaining ) /* Less data than there is left...  */
+  {
+    lengthRemaining -= nframes ;
+    bufferPos       += nframes ;
+  }
+  else  /* Read it all */
+  {
+    if ( replay_mode == SL_SAMPLE_ONE_SHOT )
+      stop () ;
+    else
+    {
+      slScheduler::getCurrent() -> addCallBack ( callback, sample, SL_EVENT_LOOPED, magic ) ;
+      start () ;
+    }
+  }
+
+  return src ;
+}
+
diff --git a/src/slScheduler.cxx b/src/slScheduler.cxx
new file mode 100644 (file)
index 0000000..8edcf03
--- /dev/null
@@ -0,0 +1,370 @@
+
+#include "sl.h"
+
+slScheduler *slScheduler::current = NULL ;
+
+void slScheduler::init ()
+{
+  current = this ;
+
+  if ( not_working () )
+  {
+    fprintf ( stderr, "slScheduler: soundcard init failed.\n" ) ;
+    setError () ;
+    return ;
+  }
+
+  if ( getBps() != 8 )
+  {
+    fprintf ( stderr, "slScheduler: Needs a sound card that supports 8 bits per sample.\n" ) ;
+    setError () ;
+    return ;
+  }
+
+  if ( getStereo() )
+  {
+    fprintf ( stderr, "slScheduler: Needs a sound card that supports monophonic replay.\n" ) ;
+    setError () ;
+    return ;
+  }
+
+  for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
+    samplePlayer [ i ] = NULL ;
+
+  amount_left = 0 ;
+  now = 0 ;
+  num_pending_callbacks = 0 ;
+  safety_margin = 1.0 ;
+
+  mixer = NULL ;
+  mixer_buffer = NULL ;
+  spare_buffer1 [ 0 ] = NULL ;
+  spare_buffer1 [ 1 ] = NULL ;
+  spare_buffer1 [ 2 ] = NULL ;
+  spare_buffer2 [ 0 ] = NULL ;
+  spare_buffer2 [ 1 ] = NULL ;
+  spare_buffer2 [ 2 ] = NULL ;
+
+  initBuffers () ;
+}
+
+void slScheduler::initBuffers ()
+{
+  if ( not_working () ) return ;
+
+  delete mixer_buffer ;
+  delete spare_buffer1 [ 0 ] ;
+  delete spare_buffer1 [ 1 ] ;
+  delete spare_buffer1 [ 2 ] ;
+  delete spare_buffer2 [ 0 ] ;
+  delete spare_buffer2 [ 1 ] ;
+  delete spare_buffer2 [ 2 ] ;
+
+  mixer_buffer_size = getDriverBufferSize () ;
+
+  mixer_buffer = new Uchar [ mixer_buffer_size ] ;
+  memset ( mixer_buffer, 0x80, mixer_buffer_size ) ;
+
+  spare_buffer1 [ 0 ] = new Uchar [ mixer_buffer_size ] ;
+  spare_buffer1 [ 1 ] = new Uchar [ mixer_buffer_size ] ;
+  spare_buffer1 [ 2 ] = new Uchar [ mixer_buffer_size ] ;
+
+  spare_buffer2 [ 0 ] = new Uchar [ mixer_buffer_size ] ;
+  spare_buffer2 [ 1 ] = new Uchar [ mixer_buffer_size ] ;
+  spare_buffer2 [ 2 ] = new Uchar [ mixer_buffer_size ] ;
+}
+
+slScheduler::~slScheduler ()
+{
+  if ( current == this )
+    current = NULL ;
+
+  delete mixer_buffer ;
+
+  delete spare_buffer1 [ 0 ] ;
+  delete spare_buffer1 [ 1 ] ;
+  delete spare_buffer1 [ 2 ] ;
+  delete spare_buffer2 [ 0 ] ;
+  delete spare_buffer2 [ 1 ] ;
+  delete spare_buffer2 [ 2 ] ;
+}
+
+Uchar *slScheduler::mergeBlock ( Uchar *d )
+{
+  register int l = amount_left ;
+  amount_left = 0 ;
+  memset ( d, 0x80, l ) ;
+
+  return d + l ;
+}
+
+
+Uchar *slScheduler::mergeBlock ( Uchar *d, slSamplePlayer *spa )
+{
+  register int l = spa -> getAmountLeft () ;
+
+  if ( l > amount_left )
+    l = amount_left ;
+
+  amount_left -= l ;
+
+  memcpy ( d, spa->read(l, spare_buffer1[0], spare_buffer2[0]), l ) ;
+
+  return d + l ;
+}
+
+
+Uchar *slScheduler::mergeBlock ( Uchar *d, slSamplePlayer *spa, slSamplePlayer *spb )
+{
+  int la = spa -> getAmountLeft () ;
+  int lb = spb -> getAmountLeft () ;
+
+  register int l = ( la < lb ) ? la : lb ;
+
+  if ( l > amount_left )
+    l = amount_left ;
+
+  amount_left -= l ;
+
+  register Uchar *a = spa -> read ( l, spare_buffer1[0], spare_buffer2[0] ) ;
+  register Uchar *b = spb -> read ( l, spare_buffer1[1], spare_buffer2[1] ) ;
+
+  while ( l-- ) *d++ = mix ( *a++, *b++ ) ;
+
+  return d ;
+}
+
+Uchar *slScheduler::mergeBlock ( Uchar *d, slSamplePlayer *spa, slSamplePlayer *spb, slSamplePlayer *spc )
+{
+  int la = spa -> getAmountLeft () ;
+  int lb = spb -> getAmountLeft () ;
+  int lc = spc -> getAmountLeft () ;
+
+  register int l = ( la < lb ) ?
+                   (( la < lc ) ? la : lc ) :
+                   (( lb < lc ) ? lb : lc ) ;
+
+  if ( l > amount_left )
+    l = amount_left ;
+
+  amount_left -= l ;
+
+  register Uchar *a = spa -> read ( l, spare_buffer1[0], spare_buffer2[0] ) ;
+  register Uchar *b = spb -> read ( l, spare_buffer1[1], spare_buffer2[1] ) ;
+  register Uchar *c = spc -> read ( l, spare_buffer1[2], spare_buffer2[2] ) ;
+
+  while ( l-- ) *d++ = mix ( *a++, *b++, *c++ ) ;
+
+  return d ;
+}
+
+
+void slScheduler::mixBuffer ()
+{
+  register Uchar *d = mixer_buffer ;
+
+  amount_left = mixer_buffer_size ;
+
+  while ( amount_left > 0 )
+    d = mergeBlock ( d ) ;
+}
+
+
+void slScheduler::mixBuffer ( slSamplePlayer *spa )
+{
+  register Uchar *d = mixer_buffer ;
+
+  amount_left = mixer_buffer_size ;
+
+  while ( amount_left > 0 )
+  {
+    int la = spa -> getAmountLeft () ;
+
+    if ( la > 0 ) /* Buffer has data left... */
+      d = mergeBlock ( d, spa ) ;
+    else          /* Buffer is empty */
+      d = mergeBlock ( d ) ;
+  }
+}
+
+
+void slScheduler::mixBuffer ( slSamplePlayer *spa, slSamplePlayer *spb )
+{
+  register Uchar *d = mixer_buffer ;
+  amount_left = mixer_buffer_size ;
+
+  while ( amount_left > 0 )
+  {
+    int la = spa -> getAmountLeft () ;
+    int lb = spb -> getAmountLeft () ;
+
+    if ( la > 0 && lb > 0 ) /* Both buffers have data left... */
+      d = mergeBlock ( d, spa, spb ) ;
+    else
+    if ( la > 0 && lb <= 0 ) /* Only the A buffer has data left... */
+      d = mergeBlock ( d, spa ) ;
+    else
+    if ( la <= 0 && lb > 0 ) /* Only the B buffer has data left... */
+      d = mergeBlock ( d, spb ) ;
+    else                     /* Both buffers are empty */
+      d = mergeBlock ( d ) ;
+  }
+}
+
+
+
+void slScheduler::mixBuffer ( slSamplePlayer *spa, slSamplePlayer *spb,
+                              slSamplePlayer *spc )
+{
+  register Uchar *d = mixer_buffer ;
+
+  amount_left = mixer_buffer_size ;
+
+  while ( amount_left > 0 )
+  {
+    int la = spa -> getAmountLeft () ;
+    int lb = spb -> getAmountLeft () ;
+    int lc = spc -> getAmountLeft () ;
+
+    if ( lc > 0 )  /* C buffer has data left... */
+    {
+      if ( la > 0 && lb > 0 ) /* All three buffers have data left... */
+       d = mergeBlock ( d, spa, spb, spc ) ;
+      else
+      if ( la > 0 && lb <= 0 ) /* Only the A&C buffers have data left... */
+       d = mergeBlock ( d, spa, spc ) ;
+      else
+      if ( la <= 0 && lb > 0 ) /* Only the B&C buffers have data left... */
+       d = mergeBlock ( d, spb, spc ) ;
+      else                     /* Only the C buffer has data left */
+       d = mergeBlock ( d, spc ) ;
+    }
+    else
+    {
+      if ( la > 0 && lb > 0 ) /* Only the A&B buffers have data left... */
+       d = mergeBlock ( d, spa, spb ) ;
+      else
+      if ( la > 0 && lb <= 0 ) /* Only the A buffer has data left... */
+       d = mergeBlock ( d, spa ) ;
+      else
+      if ( la <= 0 && lb > 0 ) /* Only the B buffer has data left... */
+       d = mergeBlock ( d, spb ) ;
+      else                     /* All three buffers are empty */
+       d = mergeBlock ( d ) ;
+    }
+  }
+}
+
+
+void slScheduler::realUpdate ( int dump_first )
+{
+  int i ;
+
+  if ( not_working () )
+    return ;
+
+  while ( secondsUsed() <= safety_margin )
+  {
+    slSamplePlayer *psp [ 3 ] ;
+    int             pri [ 3 ] ;
+
+    pri [ 0 ] = pri [ 1 ] = pri [ 2 ] =  -1  ;
+
+    for ( i = 0 ; i < SL_MAX_SAMPLES ; i++ )
+    {
+      if ( samplePlayer [ i ] == NULL )
+       continue ;
+
+      /* Clean up dead sample players */
+
+      if ( samplePlayer [ i ] -> isDone () )
+      {
+       delete samplePlayer [ i ] ;
+       samplePlayer [ i ] = NULL ;
+       continue ;
+      }
+
+      if ( samplePlayer [ i ] -> isPaused () )
+       continue ;
+
+      int lowest = ( pri [0] <= pri [2] ) ?
+                    (( pri [0] <= pri [1] ) ? 0 : 1 ) :
+                    (( pri [1] <= pri [2] ) ? 1 : 2 ) ;
+
+      if ( samplePlayer[i]->getPriority() > pri[lowest] )
+      {
+       psp[lowest] = samplePlayer[i] ;
+       pri[lowest] = samplePlayer[i]->getPriority() ;
+      }
+    }
+
+    for ( i = 0 ; i < SL_MAX_SAMPLES ; i++ )
+    {
+      if ( samplePlayer [ i ] == NULL )
+       continue ;
+
+      if ( ! samplePlayer [ i ] -> isPaused () &&
+           samplePlayer [ i ] != psp[0] &&
+           samplePlayer [ i ] != psp[1] &&
+           samplePlayer [ i ] != psp[2] )
+      {
+        samplePlayer [ i ] -> preempt ( mixer_buffer_size ) ;
+      }
+    }
+
+    if ( pri[0] < 0 ) mixBuffer () ; else
+    if ( pri[1] < 0 ) mixBuffer ( psp[0] ) ; else
+    if ( pri[2] < 0 ) mixBuffer ( psp[0], psp[1] ) ; else
+                     mixBuffer ( psp[0], psp[1], psp[2] ) ;
+
+    if ( dump_first )
+    {
+      stop () ;
+      dump_first = SL_FALSE ;
+    }
+
+    play ( mixer_buffer, mixer_buffer_size ) ;
+
+    now += mixer_buffer_size ;
+  }
+
+  flushCallBacks () ;
+}
+
+void slScheduler::addCallBack ( slCallBack c, slSample *s, slEvent e, int m )
+{
+  if ( num_pending_callbacks >= SL_MAX_CALLBACKS )
+  {
+    fprintf ( stderr, "slScheduler: Too many pending callback events!\n" ) ;
+    return ;
+  }
+
+  slPendingCallBack *p = & ( pending_callback [ num_pending_callbacks++ ] ) ;
+
+  p -> callback = c ;
+  p -> sample   = s ;
+  p -> event    = e ;
+  p -> magic    = m ;
+}
+
+void slScheduler::flushCallBacks ()
+{
+  /*
+    Execute all the callbacks that we accumulated
+    in this iteration.
+
+    This is done at the end of 'update' to reduce the risk
+    of nasty side-effects caused by 'unusual' activities
+    in the application's callback function.
+  */
+
+  while ( num_pending_callbacks > 0 )
+  {
+    slPendingCallBack *p = & ( pending_callback [ --num_pending_callbacks ] ) ;
+
+    if ( p -> callback )
+      (*(p->callback))( p->sample, p->event, p->magic ) ;
+  }
+}
+
+
diff --git a/src/sm.h b/src/sm.h
new file mode 100644 (file)
index 0000000..5e9d50d
--- /dev/null
+++ b/src/sm.h
@@ -0,0 +1,88 @@
+
+#ifndef __SM_H__
+#define __SM_H__ 1
+
+#include "slPortability.h"
+
+#ifdef SL_USING_OSS_AUDIO
+#define SMMIXER_DEFAULT_DEVICE "/dev/mixer"
+#elif defined(WIN32)
+#define SMMIXER_DEFAULT_DEVICE "mixer"
+#else
+#endif
+
+
+# define SM_TRUE  1
+# define SM_FALSE 0
+
+typedef unsigned char  Uchar  ;
+typedef unsigned short Ushort ;
+
+
+class smMixer
+{
+private:
+
+  int devices ;
+  int error ;
+  int fd ;
+
+#ifdef SL_USING_OSS_AUDIO
+  static char *labels [] = SOUND_DEVICE_LABELS ;
+
+  int ioctl ( int cmd, int param = 0 )
+  {
+    if ( error ) return param ;
+
+    if ( ::ioctl ( fd, cmd, & param ) == -1 )
+    {
+      perror ( "smMixer: ioctl" ) ;
+      error = SM_TRUE ;
+    }
+
+    return param ;
+  }
+#endif
+  void open ( char *device ) ;
+  void close () ;
+
+public:
+
+  /* Tom */
+
+  smMixer ();
+  smMixer ( char *device );
+ ~smMixer ();
+  
+  int not_working ();
+
+  /* Volume controls are in integer percentages */
+
+  int  getVolume        ( int channel             );
+  void setVolume        ( int channel, int volume ); 
+
+  void getVolume        ( int channel, int *left, int *right );
+  void setVolume        ( int channel, int  left, int  right );
+
+  void setTreble       ( int treble );
+  void setBass         ( int bass   );
+
+  void setMasterVolume ( int volume );
+  void setSynthVolume  ( int volume );
+  void setPCMVolume    ( int volume );
+  void setSpeakerVolume( int volume );
+  void setLineVolume   ( int volume );
+  void setMicVolume    ( int volume );
+  void setCDVolume     ( int volume );
+
+  void setMasterVolume ( int left, int right );
+  void setSynthVolume  ( int left, int right );
+  void setPCMVolume    ( int left, int right );
+  void setSpeakerVolume( int left, int right );
+  void setLineVolume   ( int left, int right );
+  void setMicVolume    ( int left, int right );
+  void setCDVolume     ( int left, int right );
+} ;
+
+#endif
+
diff --git a/src/smMixer.cxx b/src/smMixer.cxx
new file mode 100644 (file)
index 0000000..4ffaf7e
--- /dev/null
@@ -0,0 +1,258 @@
+#include "sm.h"
+
+#ifdef SL_USING_OSS_AUDIO
+/* ------------------------------------------------------------ */
+/* OSSAUDIO - Linux, FreeBSD                                    */
+/* ------------------------------------------------------------ */
+
+
+void smMixer::open ( char *device )
+{
+  fd = ::open ( device, O_WRONLY ) ;
+
+  if ( fd < 0 )
+  {
+    perror ( "smMixer: open" ) ;
+    error = SM_TRUE ;
+  }
+  else
+    error = SM_FALSE ;
+
+  devices = ioctl ( SOUND_MIXER_READ_DEVMASK ) ;
+}
+  
+void smMixer::close ()
+{
+  if ( fd >= 0 )
+    ::close ( fd ) ;
+}
+
+
+smMixer::smMixer ()               
+{ 
+   open ( SMMIXER_DEFAULT_DEVICE ) ; 
+} 
+
+smMixer::smMixer ( char *device ) 
+{ 
+   open ( device ) ; 
+} 
+
+smMixer::~smMixer ()               
+{ 
+   close () ; 
+}
+  
+int smMixer::not_working () 
+{ 
+   return error ; 
+}
+
+  /* Volume controls are in integer percentages */
+
+int  smMixer::getVolume ( int channel             ) 
+{ 
+   return ioctl ( MIXER_READ  ( channel ) ) & 0xFF ; 
+}
+
+
+void smMixer::setVolume ( int channel, int volume ) 
+{ 
+   ioctl ( MIXER_WRITE ( channel ), (( volume & 255 ) << 8 ) |
+                                     ( volume & 255 ) ) ; 
+}
+
+void smMixer::getVolume ( int channel, int *left, int *right )
+{
+   int vv = ioctl ( MIXER_READ ( channel ) ) ;
+
+   if ( left  ) *left  =  vv     & 0xFF ;
+   if ( right ) *right = (vv>>8) & 0xFF ;
+}
+
+void smMixer::setVolume ( int channel, int  left, int  right )
+{
+   ioctl ( MIXER_WRITE ( channel ), (( right & 255 ) << 8 ) | 
+      ( left & 255 ) ) ;
+}
+
+void smMixer::setTreble       ( int treble ) 
+{ 
+   setVolume ( SOUND_MIXER_TREBLE , treble ) ; 
+}
+
+void smMixer::setBass         ( int bass   ) 
+{ 
+   setVolume ( SOUND_MIXER_TREBLE , bass   ) ; 
+}
+
+void smMixer::setMasterVolume ( int volume ) 
+{ 
+   setVolume ( SOUND_MIXER_VOLUME , volume ) ; 
+}
+
+void smMixer::setSynthVolume  ( int volume ) 
+{ 
+   setVolume ( SOUND_MIXER_SYNTH  , volume ) ; 
+}
+
+void smMixer::setPCMVolume    ( int volume ) 
+{ 
+   setVolume ( SOUND_MIXER_PCM    , volume ) ; 
+}
+
+void smMixer::setSpeakerVolume( int volume ) 
+{ 
+   setVolume ( SOUND_MIXER_SPEAKER, volume ) ; 
+}
+
+void smMixer::setLineVolume   ( int volume ) 
+{ 
+   setVolume ( SOUND_MIXER_LINE   , volume ) ; 
+}
+
+void smMixer::setMicVolume    ( int volume ) 
+{ 
+   setVolume ( SOUND_MIXER_MIC    , volume ) ; 
+}
+
+void smMixer::setCDVolume     ( int volume ) 
+{ 
+   setVolume ( SOUND_MIXER_CD     , volume ) ; 
+}
+
+void smMixer::setMasterVolume ( int left, int right ) 
+{ 
+   setVolume ( SOUND_MIXER_VOLUME , left, right ) ; 
+}
+
+void smMixer::setSynthVolume  ( int left, int right ) 
+{  
+   setVolume ( SOUND_MIXER_SYNTH  , left, right ) ; 
+}
+
+void smMixer::setPCMVolume    ( int left, int right ) 
+{ 
+   setVolume ( SOUND_MIXER_PCM    , left, right ) ; 
+}
+
+void smMixer::setSpeakerVolume( int left, int right ) 
+{ 
+   setVolume ( SOUND_MIXER_SPEAKER, left, right ) ; 
+}
+
+void smMixer::setLineVolume   ( int left, int right ) 
+{ 
+   setVolume ( SOUND_MIXER_LINE   , left, right ) ; 
+}
+
+void smMixer::setMicVolume    ( int left, int right ) 
+{ 
+   setVolume ( SOUND_MIXER_MIC    , left, right ) ; 
+}
+
+void smMixer::setCDVolume     ( int left, int right ) 
+{ 
+   setVolume ( SOUND_MIXER_CD     , left, right ) ; 
+}
+
+#elif defined(__OpenBSD__)
+
+/* ------------------------------------------------------------ */
+/* OpenBSD 2.3                                                  */
+/* ------------------------------------------------------------ */
+
+void smMixer::open ( char *device )
+{
+}
+  
+void smMixer::close (){}
+
+smMixer::smMixer ()    { } 
+smMixer::smMixer ( char *device ) { } 
+smMixer::~smMixer ()         {}
+  
+int smMixer::not_working () 
+{ 
+   return error ; 
+}
+
+  /* Volume controls are in integer percentages */
+
+int  smMixer::getVolume ( int channel             ) { return 50 ; }
+void smMixer::getVolume ( int channel, int *left, int *right )
+{
+  if ( left  ) *left  = 50 ;
+  if ( right ) *right = 50 ;
+}
+
+void smMixer::setVolume ( int channel, int volume ) {}
+void smMixer::setVolume ( int channel, int  left, int  right ){}
+void smMixer::setTreble       ( int treble ) {}
+void smMixer::setBass         ( int bass   ) {}
+void smMixer::setMasterVolume ( int volume ) {}
+void smMixer::setSynthVolume  ( int volume ) {}
+void smMixer::setPCMVolume    ( int volume ) {}
+void smMixer::setSpeakerVolume( int volume ) {}
+void smMixer::setLineVolume   ( int volume ) {}
+void smMixer::setMicVolume    ( int volume ) {}
+void smMixer::setCDVolume     ( int volume ) {}
+void smMixer::setMasterVolume ( int left, int right ) {}
+void smMixer::setSynthVolume  ( int left, int right ) {}
+void smMixer::setPCMVolume    ( int left, int right ) {}
+void smMixer::setSpeakerVolume( int left, int right ) {}
+void smMixer::setLineVolume   ( int left, int right ) {}
+void smMixer::setMicVolume    ( int left, int right ) {}
+void smMixer::setCDVolume     ( int left, int right ) {} 
+
+
+#else
+/* ------------------------------------------------------------ */
+/* win32                                                        */
+/* ------------------------------------------------------------ */
+
+void smMixer::open ( char *device )
+{
+}
+  
+void smMixer::close (){}
+
+smMixer::smMixer ()    { } 
+smMixer::smMixer ( char *device ) { } 
+smMixer::~smMixer ()         {}
+  
+int smMixer::not_working () 
+{ 
+   return error ; 
+}
+
+  /* Volume controls are in integer percentages */
+
+int  smMixer::getVolume ( int channel             ) { return 50 ; }
+void smMixer::getVolume ( int channel, int *left, int *right )
+{
+  if ( left  ) *left  = 50 ;
+  if ( right ) *right = 50 ;
+}
+
+void smMixer::setVolume ( int channel, int volume ) {}
+void smMixer::setVolume ( int channel, int  left, int  right ){}
+void smMixer::setTreble       ( int treble ) {}
+void smMixer::setBass         ( int bass   ) {}
+void smMixer::setMasterVolume ( int volume ) {}
+void smMixer::setSynthVolume  ( int volume ) {}
+void smMixer::setPCMVolume    ( int volume ) {}
+void smMixer::setSpeakerVolume( int volume ) {}
+void smMixer::setLineVolume   ( int volume ) {}
+void smMixer::setMicVolume    ( int volume ) {}
+void smMixer::setCDVolume     ( int volume ) {}
+void smMixer::setMasterVolume ( int left, int right ) {}
+void smMixer::setSynthVolume  ( int left, int right ) {}
+void smMixer::setPCMVolume    ( int left, int right ) {}
+void smMixer::setSpeakerVolume( int left, int right ) {}
+void smMixer::setLineVolume   ( int left, int right ) {}
+void smMixer::setMicVolume    ( int left, int right ) {}
+void smMixer::setCDVolume     ( int left, int right ) {} 
+
+
+#endif