Initial revision.
This commit is contained in:
+119
@@ -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
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
SUBDIRS = src example
|
||||||
@@ -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.
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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>
|
||||||
|
|
||||||
@@ -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;......
|
||||||
@@ -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
|
||||||
@@ -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 () ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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.
|
||||||
@@ -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
@@ -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
|
||||||
|
|
||||||
@@ -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 ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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 ;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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 ) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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
@@ -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
|
||||||
Reference in New Issue
Block a user