--- /dev/null
+
+/**********************************************\
+* *
+* 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
+
--- /dev/null
+SUBDIRS = src example
--- /dev/null
+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.
+
--- /dev/null
+
+Hi!
+
+ This is the fifth prototype of Steve's 'SL' sound library.
+
+ Check out 'CHANGES' and the new HTML documentation.
+
+Steve
+
--- /dev/null
+
+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
+
--- /dev/null
+
+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
+
--- /dev/null
+
+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
+
--- /dev/null
+
+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
+
--- /dev/null
+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>
+
--- /dev/null
+
+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;......
--- /dev/null
+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
--- /dev/null
+
+
+#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 () ;
+ }
+}
+
--- /dev/null
+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.
--- /dev/null
+
+#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
+
--- /dev/null
+
+#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
+
--- /dev/null
+
+#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 ;
+ }
+}
+
+
--- /dev/null
+
+#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
+
--- /dev/null
+
+
+#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 ;
+}
+
+
--- /dev/null
+
+#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 ;
+}
+
--- /dev/null
+
+#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 ) ;
+ }
+}
+
+
--- /dev/null
+
+#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
+
--- /dev/null
+#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