1
0
Fork 0

Initial revision.

This commit is contained in:
curt 1998-07-16 17:48:11 +00:00
parent 1175179da1
commit fca7a8fa47
22 changed files with 3172 additions and 0 deletions

119
Audio/CHANGES Normal file
View file

@ -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

1
Audio/Makefile.am Normal file
View file

@ -0,0 +1 @@
SUBDIRS = src example

9
Audio/NOTICE Normal file
View file

@ -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.

9
Audio/README Normal file
View file

@ -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

13
Audio/README.freebsd Normal file
View file

@ -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

13
Audio/README.linux Normal file
View file

@ -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

13
Audio/README.openbsd Normal file
View file

@ -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

13
Audio/README.sgi Normal file
View file

@ -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

20
Audio/README.unix Normal file
View file

@ -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>

15
Audio/README.win Normal file
View file

@ -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;......

13
example/Makefile.am Normal file
View file

@ -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

89
example/example.cxx Normal file
View file

@ -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 () ;
}
}

12
src/Makefile.am Normal file
View file

@ -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.

635
src/sl.h Normal file
View file

@ -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

663
src/slDSP.cxx Normal file
View file

@ -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

92
src/slEnvelope.cxx Normal file
View file

@ -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 ;
}
}

72
src/slPortability.h Normal file
View file

@ -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

505
src/slSample.cxx Normal file
View file

@ -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 ;
}

150
src/slSamplePlayer.cxx Normal file
View file

@ -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 ;
}

370
src/slScheduler.cxx Normal file
View file

@ -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 ) ;
}
}

88
src/sm.h Normal file
View file

@ -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

258
src/smMixer.cxx Normal file
View file

@ -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