codepad
[
create a new paste
]
login
|
about
Language:
C
C++
D
Haskell
Lua
OCaml
PHP
Perl
Plain Text
Python
Ruby
Scheme
Tcl
#include <AL/al.h> #include <AL/alc.h> #include <AL/alu.h> #include <AL/alure.h> #include <AL/efx.h> #include <al/EFX-Util.h> #include <al/efx-creative.h> //#include <al/xram.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> // TODO EFX/EAX troubleshooting, stream, capture, network transceive, examine timing (add firing time, etc) #include <sndfile.h> #define RANGE(a, b, c) ((b) < (a) ? (a) : ((b) > (c) ? (c) : (b))) // EFX help (where we got the .h): Dmytry Lavrov (Public Domain code samples) //EAX //const GUID DSPROPSETID_EAX20_ListenerProperties = { 0x306a6a8, 0xb224, 0x11d2, { 0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22 } }; //const GUID DSPROPSETID_EAX20_BufferProperties = { 0x306a6a7, 0xb224, 0x11d2, { 0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22 } }; //#ifndef(AL_FORMAT_VORBIS_EXT) //#define AL_FORMAT_VORBIS_EXT 0x10003 //#endif #ifndef ALC_EXT_EFX #define AL_FILTER_TYPE 0x8001 #define AL_EFFECT_TYPE 0x8001 #define AL_FILTER_NULL 0x0000 #define AL_FILTER_LOWPASS 0x0001 #define AL_FILTER_HIGHPASS 0x0002 #define AL_FILTER_BANDPASS 0x0003 #define AL_EFFECT_NULL 0x0000 #define AL_EFFECT_EAXREVERB 0x8000 #define AL_EFFECT_REVERB 0x0001 #define AL_EFFECT_CHORUS 0x0002 #define AL_EFFECT_DISTORTION 0x0003 #define AL_EFFECT_ECHO 0x0004 #define AL_EFFECT_FLANGER 0x0005 #define AL_EFFECT_FREQUENCY_SHIFTER 0x0006 #define AL_EFFECT_VOCAL_MORPHER 0x0007 #define AL_EFFECT_PITCH_SHIFTER 0x0008 #define AL_EFFECT_RING_MODULATOR 0x0009 #define AL_EFFECT_AUTOWAH 0x000A #define AL_EFFECT_COMPRESSOR 0x000B #define AL_EFFECT_EQUALIZER 0x000C #define ALC_EFX_MAJOR_VERSION 0x20001 #define ALC_EFX_MINOR_VERSION 0x20002 #define ALC_MAX_AUXILIARY_SENDS 0x20003 #endif #ifndef ALC_MONO_SOURCES #define ALC_MONO_SOURCES 0x1010 #define ALC_STEREO_SOURCES 0x1011 #endif #ifndef AL_EFFECT_EAXREVERB #define AL_EFFECT_EAXREVERB 0x8000 #endif #ifndef ALC_CAPTURE_DEVICE_SPECIFIER /** * The Specifier string for default device */ #define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 #define ALC_DEVICE_SPECIFIER 0x1005 #define ALC_EXTENSIONS 0x1006 #define ALC_MAJOR_VERSION 0x1000 #define ALC_MINOR_VERSION 0x1001 #define ALC_ATTRIBUTES_SIZE 0x1002 #define ALC_ALL_ATTRIBUTES 0x1003 /** * Capture extension */ #define ALC_CAPTURE_DEVICE_SPECIFIER 0x310 #define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311 #define ALC_CAPTURE_SAMPLES 0x312 #endif import "ecere" // Be very careful with these two parameters // It is very dependant on the audio hardware your // user is using. It you get too large, it may work // on one persons system but not on another. // TODO Write a hardware test ! #define MAX_AUDIO_BUFFERS 64 #define MAX_AUDIO_SOURCES 16 enum ALState { empty=0, stopped=1, paused=2, playing=3 }; enum ALSoundFormat { mono8=AL_FORMAT_MONO8, mono16=AL_FORMAT_MONO16, stereo8=AL_FORMAT_STEREO8, stereo16=AL_FORMAT_STEREO16 }; /* * Compare strings, case insensitive. */ #define LOWER(c) ((c) >= 'A' && (c) <= 'Z' ? (c)+'a'-'A' : (c)) bool contains( const char *astr, const char *bstr ) { if ( astr == null ) { printf( "Str_cmp: null astr.\n" ); return false; } if ( bstr == null ) { printf( "Str_cmp: null bstr.\n" ); return false; } for ( ; *astr || *bstr; astr++, bstr++ ) if ( LOWER(*astr) != LOWER(*bstr) ) return false; return true; } // Used during Init(), maybe it shouldn't die() here... static void checkForErrors(void) { ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); ALCenum ALCerror = alcGetError(device); ALenum ALerror; if(ALCerror != ALC_NO_ERROR) printf( "ALC %s\n", alcGetString(device, ALCerror)); ALerror = alGetError(); if(ALerror != AL_NO_ERROR) printf("AL %s\n", alGetString(ALerror)); } static const int indentation = 4; static const int maxmimumWidth = 79; static void printChar(int c, int *width) { putchar(c); *width = ((c == '\n') ? 0 : ((*width) + 1)); } static void indent(int *width) { int i; for(i = 0; i < indentation; i++) printChar(' ', width); } static void printList(const char *header, char separator, const char *list) { int width = 0, start = 0, end = 0; printf("%s:\n", header); if(list == NULL || list[0] == '\0') return; indent(&width); while(1) { if(list[end] == separator || list[end] == '\0') { if(width + end - start + 2 > maxmimumWidth) { printChar('\n', &width); indent(&width); } while(start < end) { printChar(list[start], &width); start++; } if(list[end] == '\0') break; start++; end++; if(list[end] == '\0') break; printChar(',', &width); printChar(' ', &width); } end++; } printChar('\n', &width); } struct SoundVector { float x,y,z,a,b,c; //SoundVector() { y=1.0f; } float *asFloat3( ) { return &x; } float *asFloat6( ) { return &x; } }; //int unusedBuffers, unusedSources; void GetALCErrorString(ALenum err){ switch(err) { case ALC_NO_ERROR: printf("AL_NO_ERROR"); break; case ALC_INVALID_DEVICE: printf("ALC_INVALID_DEVICE"); break; case ALC_INVALID_CONTEXT: printf("ALC_INVALID_CONTEXT"); break; case ALC_INVALID_ENUM: printf("ALC_INVALID_ENUM"); break; case ALC_INVALID_VALUE: printf("ALC_INVALID_VALUE"); break; case ALC_OUT_OF_MEMORY: printf("ALC_OUT_OF_MEMORY"); break; } } bool ALError( char *tb ) { ALenum errCode; if ( ( errCode = alGetError() ) != AL_NO_ERROR ) { printf( "Audio %s Error #%d %s\n", tb, errCode, (char *) alGetString( errCode ) ); return true; } return false; } class ALBuffer : ListItem { ALuint id; inline bool valid() { if ( alIsBuffer( id ) ) return true; } float duration() { ALint bits, channels, freq, size; alGetBufferi(id, AL_BITS, &bits); alGetBufferi(id, AL_CHANNELS, &channels); alGetBufferi(id, AL_FREQUENCY, &freq); alGetBufferi(id, AL_SIZE, &size); if(ALError("ALBuffer:duration()")) { return 0.0f; } return (float) ((size / channels * 8 / bits ) / freq); } bool Close() { if ( valid() ) alDeleteBuffers(1, &(id)); if ( ALError( "ALBuffer:Close:alDeleteBuffers") ) return false; //unusedBuffers++; } ~ALBuffer() { Close(); } } class ALBuffers : LinkList<ALBuffer> { void ClearInvalid() { for ( b:this ) { if ( !b.valid() ) this.Delete(b); } } ALBuffer New() { ALBuffer b { }; alGetError(); //if ( unusedBuffers <= 0 ) { printf( "No unused buffers available when requesting New() buffer\n" ); delete b; return null; } b= ALBuffer { }; alGenBuffers(1,&(b.id)); if(ALError("ALBuffer:alGenBuffers")) { delete b; return null; } //unusedBuffers--; //printf( "#%d buffer created with ID of %d\n", unusedBuffers, b.id ); this.Add(b); return b; } }; class ALSource : ListItem { ALuint id; SoundVector position, velocity; float pitch,gain; float rolloff; ALboolean loop,relative; ALState state; ALSource() { position = SoundVector { }; velocity = SoundVector { }; pitch=1.0f; gain=1.0f; loop=AL_FALSE; relative=AL_FALSE; } inline bool valid() { if ( alIsSource( id ) ) return true; } void bindBuffer( ALBuffer buffer ) { alGetError(); alSourcei (id, AL_BUFFER, buffer.id ); alSourcef (id, AL_PITCH, pitch ); alSourcef (id, AL_GAIN, gain ); alSourcefv(id, AL_POSITION, position.asFloat3() ); alSourcefv(id, AL_VELOCITY, velocity.asFloat3() ); alSourcef (id, AL_ROLLOFF_FACTOR, rolloff ); alSourcei (id, AL_LOOPING, loop ); alSourcei (id, AL_SOURCE_RELATIVE, relative ); ALError("ALSource:bindBuffer() had an error"); state=stopped; } void bindSound( ALSound sound ) { alGetError(); alSourcei (id, AL_BUFFER, sound.waveform.buffer.id ); alSourcef (id, AL_PITCH, sound.pitch ); alSourcef (id, AL_GAIN, sound.gain ); alSourcefv(id, AL_POSITION, sound.position.asFloat3() ); alSourcefv(id, AL_VELOCITY, sound.velocity.asFloat3() ); alSourcef (id, AL_ROLLOFF_FACTOR, rolloff ); alSourcei (id, AL_LOOPING, sound.loop ); alSourcei (id, AL_SOURCE_RELATIVE, sound.relative ); ALError("ALSource:bindSound() had an error"); state=stopped; } void bindStream( ALUREStream stream ) { alGetError(); alSourcef (id, AL_PITCH, pitch ); alSourcef (id, AL_GAIN, gain ); alSourcefv(id, AL_POSITION, position.asFloat3() ); alSourcefv(id, AL_VELOCITY, velocity.asFloat3() ); alSourcef (id, AL_ROLLOFF_FACTOR, rolloff ); alSourcei (id, AL_LOOPING, AL_FALSE ); // handled elsewhere alSourcei (id, AL_SOURCE_RELATIVE, relative ); stream.source=this; ALError("ALSource:bindStream() had an error"); state=stopped; } void Detach() { if ( state == empty ) { printf( "ALSource:Detach:Empty source attempted. (Cannot dump a buffer from an empty source)\n" ); return; } else if ( state != stopped ) { Stop(); } if ( valid() ) { alSourcei(id,AL_BUFFER,0); state=empty; alGetError(); } } inline void Stop() { if ( valid() && state == playing ) { alGetError(); alSourceStop(id); alGetError(); state=stopped; } } inline void Pause() { if ( valid() && state == playing ) { alGetError(); alSourcePause(id); alGetError(); state=paused; } } inline void Play() { if ( valid() && state != playing ) { ALError("ALSound:Pre-Play()"); alSourcePlay(id); ALError("ALSound:Play() had an error."); alGetError(); state=playing; } } inline void Resume() { Play(); } // void PauseAll() { if ( valid() && state == playing ) Pause(); if ( next ) next.PauseAll(); } // void ResumeAll() { if ( valid() && state == paused ) Resume(); if ( next ) next.ResumeAll(); } bool Close( ) { if ( valid() ) { if ( state != empty ) this.Detach(); alDeleteSources(1, &(id)); if ( ALError( "ALSource:Close:alDeleteSources") ) return false; //unusedSources++; return true; } return false; } // void rehead( ALSource a ) { ALSource b=this; for ( ; b; b=b.next ) b.head=a; } ~ALSource() { Close(); } } class ALSources : LinkList<ALSource> { // List functions for managing a multi-source list. ALSource AddNew() { ALSource s = null; // if( unusedSources > 0 ) { uint id; alGenSources(1,&id); if(!ALError("ALSource:WAV:alGenSources")) { //unusedSources--; Insert(null, s = { id = id }); } } return s; } } /* ALURE stream */ class ALUREStream { public union { LinkElement<thisclass> link; struct { thisclass prev, next; }; }; ALSoundManager manager; alureStream *stream; char *name; int bufferSize; int usesBuffers; uint samples; float duration; float refreshRate; // ALuint *buf; ALSource source; bool created; bool loop; bool badError; SoundVector position, velocity; float pitch,gain; float threadDelay; bool terminated; bufferSize=128*1024; usesBuffers=3;//3; threadDelay=0.01f; ~ALUREStream() { alureDestroyStream(stream, 0, null);// usesBuffers, buf); delete source; //unusedBuffers+=usesBuffers; delete name; } inline bool Playing() { return ( source && source.state == playing ); } // uint Main() { Sleep(threadDelay); DelayExpired(); return 0; } void Stop() { if(created) { alureStopSource(source.id,AL_FALSE); } } //terminated = true; ((GuiApplication)__thisModule).Unlock(); Wait(); ((GuiApplication)__thisModule).Lock(); } } bool LoadIntoSource(char *fn, ALSource s, bool CalcSize ) { name=CopyString(fn); if ( !source ) { printf("ALUREStream:Create complains the required source was not provided.\n" ); return false; } //if ( usesBuffers > unusedBuffers ) { printf("ALUREStream:Create Not enough buffers available. Requested: %d Available: %d\n", usesBuffers, unusedBuffers ); return false; } alGetError(); source=s; // if ( buf ) { printf( "ALUREStream:Create warns, the buffers were already created, was .Create() mistakenly called twice?\n" ); delete buf; } //buf=new ALuint[usesBuffers]; //unusedBuffers-=usesBuffers; stream=alureCreateStreamFromFile((ALchar *) fn,bufferSize,0/*usesBuffers*/,null);//buf); if ( !stream ) { printf( "ALUREStream:Create could not load the file: %s\n", fn, alureGetErrorString()); return false; } if ( CalcSize ) CalculateSize(fn); return (created=true); } virtual void OnComplete() { } bool Play() { if ( !this ) { printf( "ALUREStream:Play:Called on a null object.\n" ); return false; } if ( !source ) { printf( "ALUREStream:Play:No source defined for the stream '%s'. Did it load properly?\n", name ); return false; } if ( source.state == stopped ) { printf ( "Play() was called on a stream.\n" ); alGetError(); // alSourceQueueBuffers(source.id,usesBuffers,buf); // if ( ALError("ALUREStream:Play:alSourceQueueBuffers") ) { printf( "ALUREStream:Play failed to queue buffers.\n" ); return false; } // alSourcePlay(source.id); alurePlaySourceStream(source.id,stream,usesBuffers,0/*# of loops*/,null,null); // add eos_callback tie-in here source.state=playing; // if ( ALError("ALUREStream:Play:alSourcePlay") ) { printf( "ALUREStream:Play failed to start source.\n" ); return false; } // this.timer.delay = (1.0f/refreshRate); // this.timer.Start(); // Create(); } else if ( source.state == paused || source.state==stopped ) { source.Resume(); return true; } else if ( source.state == empty ) { printf( "ALUREStream:Play called on an empty source (no buffer selected).\n" ); return false; } else if ( source.state == playing ) { printf( "ALUREStream:Play() called on a playing stream.\n" ); return true; } return true; } virtual void BetweenFrames() { } virtual void OnError() { } // Slightly inefficient, but precise. int CalculateSize( char * fn ) { ALuint total = 0; ALuint b; ALint freq = 0; alureStream *s; s = alureCreateStreamFromFile( (ALchar *) fn, 19200, 1, &b); if(s) { do { ALint size, bits, channels; alGetBufferi(b, AL_SIZE, &size); alGetBufferi(b, AL_BITS, &bits); alGetBufferi(b, AL_CHANNELS, &channels); if(!freq) alGetBufferi(b, AL_FREQUENCY, &freq); total += bits / channels * 8 / bits; } while(alureBufferDataFromStream(s, 1, &b) > 0); alureDestroyStream(s,1,&b); } duration=(float)total/(float)freq; samples=(uint) total; } } class ALUREStreams : LinkList<ALUREStream, link=ALUREStream::link> {}; class ALCaptureStream { ALSoundFormat format; int sampleFactor; public: property ALSoundFormat format { get { return format; } set { format=value; switch ( (ALSoundFormat) value ) { case mono8: sampleFactor=1; break; case mono16: case stereo8: sampleFactor=2; break; case stereo16: sampleFactor=4; break; } } } uint frequency; uint bufferSize; int samples; ALuint available; ALCdevice *captureDevice; char *deviceName; bool capturing; byte *target; int ofs; ALCaptureStream() { format=stereo16; sampleFactor=4; } void Start() { if ( captureDevice ) { alcCaptureStart(captureDevice); capturing=true; } } int *Acquire() { if ( capturing ) { int *buffer; alcGetIntegerv(captureDevice, ALC_CAPTURE_SAMPLES, 1, &available); buffer = new byte[available*sampleFactor]; memset(buffer,0,available); alcCaptureSamples(captureDevice,buffer,(ALuint) available); return buffer; } return null; } void AcquireTo( byte **buf ) { if ( capturing ) { if ( *buf ) delete *buf; alcGetIntegerv(captureDevice, ALC_CAPTURE_SAMPLES, 1, &available); *buf = new byte[available*sampleFactor]; target = *buf; alcCaptureSamples(captureDevice,*buf,(ALuint) available); } else { delete *buf; *buf=null; } } void AcquireAppend( byte *pre ) { if ( capturing ) { int *post=&(pre[ofs]); alcGetIntegerv(captureDevice, ALC_CAPTURE_SAMPLES, 1, &available); ofs+=available; alcCaptureSamples(captureDevice,post,(ALuint) available); } } void Stop() { if ( captureDevice ) { alcCaptureStop(captureDevice); capturing=false; OnCaptureComplete(); } } virtual void OnCaptureComplete() { } bool Init( char *name ) { deviceName=CopyString(name); captureDevice = alcCaptureOpenDevice( (ALCchar *) name, frequency, format, (ALCsizei) bufferSize ); if ( !captureDevice ) { printf( "ALCaptureStream:Init:alcCaptureOpenDevice -> unable to open a device\n" ); return false; } return true; } ~ALCaptureStream() { } } class ALSound { public union { LinkElement<thisclass> link; struct { thisclass prev, next; }; }; ALWaveForm waveform; char *name; uint id; float duration; bool deleteMe; ALenum format; ALvoid *data; ALsizei size,freq; ALboolean loop, relative; ALSource source; // sources are points of emitting sound. SoundVector position, velocity, direction; float pitch,gain,min_gain,max_gain,distance,rolloff; bool boundToSource; bool lastFramePlayState; bool Restart; bool Release() { alSourceStop( id ); } int NextAvailableID( int max ) { ALSound s; int i; bool *notavailable= new bool[max]; for ( s=this; s; s=s.next ) notavailable[s.id-1]=true; for ( i=0; i<max; i++ ) if ( notavailable[i] == false ) { delete notavailable; return i+1; } delete notavailable; return -1; } bool Play( ) { int sourceAudioState = 0; WhenPlayed(); if ( !source ) { printf( "Audio %s had no source.\n", waveform.filename ); return false; } alGetError(); alGetSourcei( source.id, AL_SOURCE_STATE, &sourceAudioState ); if ( sourceAudioState == AL_PLAYING ) { if ( Restart ) Stop( id ); else return false; } alSourcePlay( source.id ); if ( ALError( "ALSound:Play:alSourcePlay") ) return false; lastFramePlayState=true; source.state=playing; alGetError(); return true; } bool Pause( ) { WhenPaused(); alGetError(); alSourcePause( source.id ); if ( ALError( "ALSound:Pause:alSourcePause") ) return false; lastFramePlayState=false; source.state=paused; alGetError(); return true; } bool Playing() { int sourceAudioState = 0; if ( !source ) return false; alGetSourcei( source.id, AL_SOURCE_STATE, &sourceAudioState ); if ( sourceAudioState == AL_PLAYING ) source.state=playing; if ( sourceAudioState == AL_PAUSED ) source.state=paused; return ( source.state == playing ); } // If the sound was paused the sound will resume, else it will play from the beginning. bool Resume( ) { int sourceAudioState = 0; WhenResumed(); alGetError(); alGetSourcei( source.id, AL_SOURCE_STATE, &sourceAudioState ); if ( sourceAudioState == AL_PLAYING ) return true; if ( sourceAudioState == AL_PAUSED ) { alSourcePlay( source.id ); if ( ALError( "Resume:alSourcePlay") ) return false; } if ( ALError( "ALSound:Resume:alSourcePlay") ) return false; lastFramePlayState=true; source.state=playing; alGetError(); return true; } // Make sure the audio source ident is valid and usable bool Stop( ) { alGetError(); alSourceStop( source.id ); if ( ALError( "ALSound:Stop:alSourceStop") ) return false; lastFramePlayState=false; source.state=stopped; alGetError(); return true; } bool position( ) { alGetError(); alSourcefv(source.id, AL_POSITION, position.asFloat3() ); if ( ALError( "ALSound:position:alSourcefv:AL_POSITION" ) ) return false; return true; } bool SetPVD( ) { if ( !Playing() ) return true; alGetError(); alSourcefv(source.id, AL_POSITION, position.asFloat3() ); if ( ALError( "ALSound:SetPVD:alSourcefv:AL_POSITION" ) ) return false; alSourcefv(source.id, AL_VELOCITY, velocity.asFloat3() ); if ( ALError( "ALSound:SetPVD:alSourcefv:AL_VELOCITY" ) ) return false; alSourcefv(source.id, AL_DIRECTION, direction.asFloat3() ); if ( ALError( "ALSound:SetPVD:alSourcefv:AL_DIRECTION" ) ) return false; alGetError(); return true; } bool SetSound( float maxDistance, float minGain, float maxGain, float rollOff ) { alGetError(); alSourcef(source.id, AL_MAX_DISTANCE, distance=maxDistance ); if ( ALError( "ALSound:SetSound:alSourcef:AL_MAX_DISTANCE" ) ) return false; alSourcef(source.id, AL_MIN_GAIN, min_gain=minGain ); if ( ALError( "ALSound:SetSound:alSourcef:AL_MIN_GAIN" ) ) return false; alSourcef(source.id, AL_MAX_GAIN, max_gain=maxGain ); if ( ALError( "ALSound:SetSound:alSourcef:AL_MAX_GAIN" ) ) return false; alSourcef(source.id, AL_ROLLOFF_FACTOR, rolloff =rollOff ); if ( ALError( "ALSound:SetSound:alSourcef:AL_ROLLOFF_FACTOR" ) ) return false; return true; } ALSource UpdateSource() { alGetError(); // alSourcei (source.id, AL_BUFFER, buffer.id ); alSourcef (source.id, AL_PITCH, pitch ); alSourcef (source.id, AL_GAIN, gain ); alSourcef (source.id, AL_MAX_DISTANCE, distance ); if ( ALError( "ALSound:AddSource:AL_MAX_DISTANCE" ) ) { delete source; return null; } alSourcef (source.id, AL_MIN_GAIN, min_gain ); if ( ALError( "ALSound:AddSource:AL_MIN_GAIN" ) ) { delete source; return null; } alSourcef (source.id, AL_MAX_GAIN, max_gain ); if ( ALError( "ALSound:AddSource:AL_MAX_GAIN" ) ) { delete source; return null; } alSourcef (source.id, AL_ROLLOFF_FACTOR, rolloff ); if ( ALError( "ALSound:AddSource:AL_ROLLOFF_FACTOR" ) ) { delete source; return null; } alSourcefv(source.id, AL_POSITION, position.asFloat3() ); if ( ALError( "ALSound:AddSource:AL_POSITION" ) ) { delete source; return null; } alSourcefv(source.id, AL_VELOCITY, velocity.asFloat3() ); if ( ALError( "ALSound:AddSource:AL_VELOCITY" ) ) { delete source; return null; } alSourcefv(source.id, AL_DIRECTION, direction.asFloat3() ); if ( ALError( "ALSound:AddSource:AL_DIRECTION" ) ) { delete source; return null; } alSourcei (source.id, AL_LOOPING, (ALboolean) loop ); alSourcePlay(source.id); return source; } void AssignSource( ALSource s ) { alGetError(); if ( source ) { printf( "ALSound:AssignSource:Error! Attempted to assign a source when there already was one.\n" ); return; } source=s; alSourcei (source.id, AL_BUFFER, waveform.buffer.id ); UpdateSource(); } ALSource AddSource() { if ( !source ) { ALSource s { }; alGetError(); alGenSources(1, &(s.id)); if (alGetError() != AL_NO_ERROR) { printf("ALSound:AddSource(): Error generating audio source."); return; } alSourcei (s.id, AL_BUFFER, waveform.buffer.id ); alSourcef (s.id, AL_PITCH, pitch ); alSourcef (s.id, AL_GAIN, gain ); alSourcef (s.id, AL_MAX_DISTANCE, distance ); if ( ALError( "ALSound:AddSource:AL_MAX_DISTANCE" ) ) { delete source; return null; } alSourcef (s.id, AL_MIN_GAIN, min_gain ); if ( ALError( "ALSound:AddSource:AL_MIN_GAIN" ) ) { delete source; return null; } alSourcef (s.id, AL_MAX_GAIN, max_gain ); if ( ALError( "ALSound:AddSource:AL_MAX_GAIN" ) ) { delete source; return null; } alSourcef (s.id, AL_ROLLOFF_FACTOR, rolloff ); if ( ALError( "ALSound:AddSource:AL_ROLLOFF_FACTOR" ) ) { delete source; return null; } alSourcefv(s.id, AL_POSITION, position.asFloat3() ); if ( ALError( "ALSound:AddSource:AL_POSITION" ) ) { delete source; return null; } alSourcefv(s.id, AL_VELOCITY, velocity.asFloat3() ); if ( ALError( "ALSound:AddSource:AL_VELOCITY" ) ) { delete source; return null; } alSourcefv(s.id, AL_DIRECTION, direction.asFloat3() ); if ( ALError( "ALSound:AddSource:AL_DIRECTION" ) ) { delete source; return null; } alSourcei (s.id, AL_LOOPING, (ALboolean) loop ); alSourcePlay(s.id); this.source=s; return s; } printf( "ALSound:AddSource() - source Already Created; File: %s\n", waveform.filename ); return null; } void PrintInfo( ) { } bool *ThrowASwitch; virtual void WhenPlayed ( ){ } virtual void WhenPaused ( ){ } virtual void WhenResumed ( ){ } virtual void WhenComplete ( ){ if ( ThrowASwitch ) *ThrowASwitch=true; } virtual void BetweenFrames( ){ } void _BetweenFrames() { int state; alGetSourcei(source.id, AL_SOURCE_STATE, &state); if ( AL_PLAYING == state ) BetweenFrames(); if ( !(AL_PLAYING == state) && lastFramePlayState ) { WhenComplete(); this.Release(); this.deleteMe=true; //printf( "%s sound cleared for deletion.\n", name ); } lastFramePlayState=(AL_PLAYING == state); } ~ALSound() { // printf( "Deleting sound %s\n", name ); delete source; delete name; } } class ALSounds : LinkList<ALSound, link=ALSound::link> { bool inList( char *fn ) { for ( s : this; contains(fn,s.name)) return true; return false; } ALSound findInList( char *fn ) { for ( s : this; contains(fn,s.name) ) return s; return null; } void DeleteDone() { ALSound s,n; for ( s=this.first; s; s=n ) { n=s.next; if ( s.deleteMe ) Delete((void *)s); } } } class ALCDeviceContext : ListItem { ALCcontext* context; ALCdevice* device; char *deviceName; bool closed; void PickDefault() { device=alcOpenDevice(null); context=alcCreateContext(device,null); alcMakeContextCurrent(context); closed=false; } void Init( char *context, void *variables ) { device = alcOpenDevice(context); this.context = alcCreateContext(device, variables); alcMakeContextCurrent(this.context); closed=false; } void Close() { context = alcGetCurrentContext(); device = alcGetContextsDevice(context); alcMakeContextCurrent(null); alcDestroyContext(context); alcCloseDevice(device); closed=true; } void DeviceInfo( ) { printf( "Sound devices available:\n" ); if ( alcIsExtensionPresent( null, "ALC_ENUMERATION_EXT" ) == AL_TRUE ) { printf( "ALC_DEVICE_SPECIFIER: %s\n", (char*) alcGetString( device, ALC_DEVICE_SPECIFIER ) ); printf( "ALC_DEFAULT_DEVICE_SPECIFIER: %s\n", (char*) alcGetString( null, ALC_DEFAULT_DEVICE_SPECIFIER ) ); printf( "ALC_EXTENSIONS: %s\n", (char*) alcGetString( null, ALC_EXTENSIONS ) ); } else printf( " ... enumeration error.\n" ); } ~ALCDeviceContext() { if (!closed) Close(); } } class ALCDeviceContexts : LinkList<ALCDeviceContext>; enum EFXType { null=0, reverb=1, chorus=2, distortion=3, echo=4, flanger=5, frequencyShifter=6, vocalMorpher=7, pitchShifter=8, ringModulator=9, autoWah=10, compressor=11, equalizer=12 }; enum EFXWaveForm { sinusoid=0, triangle=1 }; enum EFXDirection { down=0, up=1, off=2 }; enum EFXPhoneme { A=0, E=1, I=2, O=3, U=4, AA=5, AE=6, AH=7, AO=8, EH=9, ER=10, IH=11, IY=12, UH=13, AW=14, B=15, D=16, F=17, G=18, J=19, K=20, L=21, M=22, N=23, P=24, R=25, S=26, T=27, V=28, Z=29 }; enum EFXWaveForm3a { sinusoid=0, triangle=1, sawtooth=2 }; enum EFXWaveForm3b { sinusoid=0, sawtooth=1, square=2 }; class EFXAuxSlot : ListItem { EFX efx; ALuint id; bool Create() { alGetError(); efx.alGenAuxiliaryEffectSlots(1,&id); if ( ALError("EFXAuxSlot:Create:alGenAuxiliaryEffectSlots") ) return false; return true; } bool Destroy() { alGetError(); efx.alDeleteAuxiliaryEffectSlots(1,&id); if ( ALError("EFXAuxSlot:Destroy:alDeleteAuxiliaryEffectSlots") ) return false; return true; } } class EFXAuxSlots : LinkList<EFXAuxSlot>; class EFXEffect { EFX efx; EFXAuxSlot aux; uint id; uint type; uint firstParameter,lastParameter; float directFilter, auxSendFilter, airAbsorption, roomRolloff, coneOuterGainHF, directFilterGainHF, auxSendFilterGainAuto, auxSendFilterGainHFAuto; bool Create() { alGetError(); if ( aux ) if ( !aux.Destroy() ) { return false; } delete aux; aux = EFXAuxSlot { }; if ( !aux.Create() ) { return false; } efx.alGenEffects(1,&id); if ( ALError("EFXEffect:Create:alGenEffects") ) return false; efx.alEffecti(id,AL_EFFECT_TYPE,type); if ( ALError("EFXEffect:Create:alEffecti") ) { efx.alDeleteEffects(1,&id); return false; } efx.alAuxiliaryEffectSloti(aux.id, AL_EFFECTSLOT_EFFECT, id); } bool Destroy() { alGetError(); efx.alAuxiliaryEffectSloti(aux.id, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL); efx.alDeleteEffects(1,&id); if ( ALError("EFXEffect:Destroy:alDeleteEffects") ) return false; } void ApplySharedEffectParameters() { } } enum EAXReverbPresets { hanger=2,bathroom=1 }; class EAXReverb : EFXEffect { float environmentSize, environmentDiffusion, density, diffusion, gain, gainHF, gainLF, decayTime, decayHFRatio, decayLFRatio, reflectionsGain, reflectionsDelay, lateGain, lateDelay, reverbDelay, echoTime, echoDepth, modulationTime, modulationDepth, airAbsorptionGainHF, referenceHF, referenceLF, roomRolloffFactor; SoundVector reflectionsPan, latePan; int room, roomHF, roomLF, reverb, flags, reflections, environment; bool decayHFLimit; EAXReverb() { // Defaulted to bathroom effect reflectionsPan = SoundVector { }; latePan = SoundVector { }; } bool Apply() { alGetError(); efx.alEffectf(id, AL_EAXREVERB_DENSITY, density); efx.alEffectf(id, AL_EAXREVERB_DIFFUSION, diffusion); efx.alEffectf(id, AL_EAXREVERB_GAIN, gain); efx.alEffectf(id, AL_EAXREVERB_GAINHF, gainHF); efx.alEffectf(id, AL_EAXREVERB_GAINLF, gainLF); efx.alEffectf(id, AL_EAXREVERB_DECAY_TIME, decayTime); efx.alEffectf(id, AL_EAXREVERB_DECAY_HFRATIO, decayHFRatio); efx.alEffectf(id, AL_EAXREVERB_DECAY_LFRATIO, decayLFRatio); efx.alEffectf(id, AL_EAXREVERB_REFLECTIONS_GAIN, reflectionsGain); efx.alEffectf(id, AL_EAXREVERB_REFLECTIONS_DELAY, reflectionsDelay); efx.alEffectfv(id, AL_EAXREVERB_REFLECTIONS_PAN, reflectionsPan.asFloat3()); efx.alEffectf(id, AL_EAXREVERB_LATE_REVERB_GAIN, lateGain); efx.alEffectf(id, AL_EAXREVERB_LATE_REVERB_DELAY, lateDelay); efx.alEffectfv(id, AL_EAXREVERB_LATE_REVERB_PAN, latePan.asFloat3()); efx.alEffectf(id, AL_EAXREVERB_ECHO_TIME, echoTime); efx.alEffectf(id, AL_EAXREVERB_ECHO_DEPTH, echoDepth); efx.alEffectf(id, AL_EAXREVERB_MODULATION_TIME, modulationTime); efx.alEffectf(id, AL_EAXREVERB_MODULATION_DEPTH, modulationDepth); efx.alEffectf(id, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, airAbsorptionGainHF); efx.alEffectf(id, AL_EAXREVERB_HFREFERENCE, referenceHF); efx.alEffectf(id, AL_EAXREVERB_LFREFERENCE, referenceLF); efx.alEffectf(id, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, roomRolloffFactor); efx.alEffecti(id, AL_EAXREVERB_DECAY_HFLIMIT, (ALboolean) decayHFLimit); if ( ALError("EAXReverb:Apply") ) return false; return true; } void Preset( EAXReverbPresets preset ) { switch ( preset ) { default: case bathroom: environment=3; environmentSize=1.4f; environmentDiffusion=1.000f; room=-1000; roomHF=-1200; roomLF=0; decayTime=1.49f; decayHFRatio=0.54f; decayLFRatio=1.00f; reflections=-370; reflectionsDelay=0.007f; reflectionsPan.x=0.0f; reflectionsPan.y=0.0f; reflectionsPan.z=0.0f; reverb=1030; reverbDelay=0.011f; latePan.x=0.00f; latePan.y=0.00f; latePan.z=0.00f; echoTime=0.250f; echoDepth=0.000f; modulationTime=0.250f; modulationDepth=0.000f; airAbsorptionGainHF=-5.0f; referenceHF=5000.0f; referenceLF=250.0f; roomRolloffFactor=0.00f; flags=0x3f; break; } } } class EFXReverb : EFXEffect { float density, diffusion, gain, gainHF, decayTime, decayHFRatio, reflectionsGain, reflectionsDelay, lateGain, lateDelay, airAbsorptionGainHF, roomRolloffFactor; bool decayHFLimit; EFXReverb() { density = AL_REVERB_DEFAULT_DENSITY; diffusion = AL_REVERB_DEFAULT_DIFFUSION; gain = AL_REVERB_DEFAULT_GAIN; gainHF = AL_REVERB_DEFAULT_GAINHF; decayTime = AL_REVERB_DEFAULT_DECAY_TIME; decayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO; reflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN; reflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY; lateGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN; lateDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY; airAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF; roomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; decayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; } public: property float density { get { return density; } set { density =RANGE(AL_REVERB_MIN_DENSITY, value, AL_REVERB_MAX_DENSITY); } } property float diffusion { get { return diffusion; } set { diffusion =RANGE(AL_REVERB_MIN_DIFFUSION, value, AL_REVERB_MAX_DIFFUSION); } } property float gain { get { return gain; } set { gain =RANGE(AL_REVERB_MIN_GAIN, value, AL_REVERB_MAX_GAIN); } } property float gainHF { get { return gainHF; } set { gainHF =RANGE(AL_REVERB_MIN_GAINHF, value, AL_REVERB_MAX_GAINHF); } } property float decayTime { get { return decayTime; } set { decayTime =RANGE(AL_REVERB_MIN_DECAY_TIME, value, AL_REVERB_MAX_DECAY_TIME); } } property float decayHFRatio { get { return decayHFRatio; } set { decayHFRatio =RANGE(AL_REVERB_MIN_DECAY_HFRATIO, value, AL_REVERB_MAX_DECAY_HFRATIO); } } property float reflectionsGain { get { return reflectionsGain; } set { reflectionsGain =RANGE(AL_REVERB_MIN_REFLECTIONS_GAIN, value, AL_REVERB_MAX_REFLECTIONS_GAIN); } } property float reflectionsDelay { get { return reflectionsDelay; } set { reflectionsDelay =RANGE(AL_REVERB_MIN_LATE_REVERB_DELAY, value, AL_REVERB_MAX_REFLECTIONS_DELAY); } } property float lateGain { get { return lateGain; } set { lateGain =RANGE(AL_REVERB_MIN_LATE_REVERB_GAIN, value, AL_REVERB_MAX_LATE_REVERB_GAIN); } } property float lateDelay { get { return lateDelay; } set { lateDelay =RANGE(AL_REVERB_MIN_LATE_REVERB_DELAY, value, AL_REVERB_MAX_LATE_REVERB_DELAY); } } property float airAbsorptionGainHF { get { return airAbsorptionGainHF; } set { airAbsorptionGainHF =RANGE(AL_REVERB_MIN_AIR_ABSORPTION_GAINHF, value, AL_REVERB_MAX_AIR_ABSORPTION_GAINHF); } } property float roomRolloffFactor { get { return roomRolloffFactor; } set { roomRolloffFactor =RANGE(AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR, value, AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR); } } property bool decayHFLimit { get { return decayHFLimit; } set { decayHFLimit =RANGE(AL_REVERB_MIN_DECAY_HFLIMIT, value, AL_REVERB_MAX_DECAY_HFLIMIT); } } void Apply() { } void Update() { } void Print() { } } class EFXChorus : EFXEffect { EFXWaveForm waveform; int phase; float rate, depth, feedback, delay; EFXChorus() { waveform = (EFXWaveForm) AL_CHORUS_DEFAULT_WAVEFORM; phase = AL_CHORUS_DEFAULT_PHASE; rate = AL_CHORUS_DEFAULT_RATE; depth = AL_CHORUS_DEFAULT_DEPTH; feedback = AL_CHORUS_DEFAULT_FEEDBACK; delay = AL_CHORUS_DEFAULT_DELAY; } public: property float phase { get { return phase; } set { phase =RANGE(AL_CHORUS_MIN_PHASE, value, AL_CHORUS_MAX_PHASE); } } property float rate { get { return rate; } set { rate =RANGE(AL_CHORUS_MIN_RATE, value, AL_CHORUS_MAX_RATE); } } property float depth { get { return depth; } set { depth =RANGE(AL_CHORUS_MIN_DEPTH, value, AL_CHORUS_MAX_DEPTH); } } property float feedback { get { return feedback; } set { feedback =RANGE(AL_CHORUS_MIN_FEEDBACK, value, AL_CHORUS_MAX_FEEDBACK); } } property float delay { get { return delay; } set { delay =RANGE(AL_CHORUS_MIN_DELAY, value, AL_CHORUS_MAX_DELAY); } } void Apply() { } void Update() { } void Print() { } } class EFXDistortion : EFXEffect { float edge, gain, cutoff, eqCenter, eqBandwidth; EFXDistortion() { edge = AL_DISTORTION_DEFAULT_EDGE; gain = AL_DISTORTION_DEFAULT_GAIN; cutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF; eqCenter = AL_DISTORTION_DEFAULT_EQCENTER; eqBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH; } public: property float edge { get { return edge; } set { edge =RANGE(AL_DISTORTION_MIN_EDGE, value, AL_DISTORTION_MAX_EDGE); } } property float gain { get { return gain; } set { gain =RANGE(AL_DISTORTION_MIN_GAIN, value, AL_DISTORTION_MAX_GAIN); } } property float cutoff { get { return cutoff; } set { cutoff =RANGE(AL_DISTORTION_MIN_LOWPASS_CUTOFF, value, AL_DISTORTION_MAX_LOWPASS_CUTOFF); } } property float eqCenter { get { return eqCenter; } set { eqCenter =RANGE(AL_DISTORTION_MIN_EQCENTER, value, AL_DISTORTION_MAX_EQCENTER); } } property float eqBandwidth { get { return eqBandwidth; } set { eqBandwidth =RANGE(AL_DISTORTION_MIN_EQBANDWIDTH, value, AL_DISTORTION_MAX_EQBANDWIDTH); } } void Apply() { } void Update() { } void Print() { } } class EFXEcho : EFXEffect { float delay, delayLR, damping, feedback, spread; EFXEcho() { delay = AL_ECHO_DEFAULT_DELAY; delayLR = AL_ECHO_DEFAULT_LRDELAY; damping = AL_ECHO_DEFAULT_DAMPING; feedback = AL_ECHO_DEFAULT_FEEDBACK; spread = AL_ECHO_DEFAULT_SPREAD; } public: property float delay { get { return delay; } set { delay =RANGE(AL_ECHO_MIN_DELAY, value, AL_ECHO_MAX_DELAY); } } property float delayLR { get { return delayLR; } set { delayLR =RANGE(AL_ECHO_MIN_LRDELAY, value, AL_ECHO_MAX_LRDELAY); } } property float damping { get { return damping; } set { damping =RANGE(AL_ECHO_MIN_DAMPING, value, AL_ECHO_MAX_DAMPING); } } property float feedback { get { return feedback; } set { feedback =RANGE(AL_ECHO_MIN_FEEDBACK, value, AL_ECHO_MAX_FEEDBACK); } } property float spread { get { return spread; } set { spread =RANGE(AL_ECHO_MIN_SPREAD, value, AL_ECHO_MAX_SPREAD); } } void Apply() { } void Update() { } void Print() { } } class EFXFlanger : EFXEffect { EFXWaveForm waveform; int phase; float rate, depth, feedback, delay; EFXFlanger() { waveform = (EFXWaveForm) AL_FLANGER_DEFAULT_WAVEFORM; phase = AL_FLANGER_DEFAULT_PHASE; rate = AL_FLANGER_DEFAULT_RATE; depth = AL_FLANGER_DEFAULT_DEPTH; feedback = AL_FLANGER_DEFAULT_FEEDBACK; delay = AL_FLANGER_DEFAULT_DELAY; } public: property float phase { get { return phase; } set { phase =RANGE(AL_FLANGER_MIN_PHASE, value, AL_FLANGER_MAX_PHASE); } } property float rate { get { return rate; } set { rate =RANGE(AL_FLANGER_MIN_RATE, value, AL_FLANGER_MAX_RATE); } } property float depth { get { return depth; } set { depth =RANGE(AL_FLANGER_MIN_DEPTH, value, AL_FLANGER_MAX_DEPTH); } } property float feedback { get { return feedback; } set { feedback =RANGE(AL_FLANGER_MIN_FEEDBACK, value, AL_FLANGER_MAX_FEEDBACK); } } property float delay { get { return delay; } set { delay =RANGE(AL_FLANGER_MIN_DELAY, value, AL_FLANGER_MAX_DELAY); } } void Apply() { } void Update() { } void Print() { } } class EFXFrequencyShift : EFXEffect { float freq; EFXDirection L,R; EFXFrequencyShift() { freq = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; L = (EFXDirection) AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; R = (EFXDirection) AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; } public: property float freq { get { return freq; } set { freq =RANGE(AL_FREQUENCY_SHIFTER_MIN_FREQUENCY, value, AL_FREQUENCY_SHIFTER_MAX_FREQUENCY); } } void Apply() { } void Update() { } void Print() { } } class EFXVocalMorph : EFXEffect { EFXPhoneme phonemeA, phonemeB; int phonemeACoarseTuning, phonemeBCoarseTuning; EFXWaveForm3a waveform; float rate; EFXReverb() { phonemeA = (EFXPhoneme) AL_VOCAL_MORPHER_DEFAULT_PHONEMEA; phonemeB = (EFXPhoneme) AL_VOCAL_MORPHER_DEFAULT_PHONEMEB; phonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING; phonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING; waveform = (EFXWaveForm3a) AL_VOCAL_MORPHER_DEFAULT_WAVEFORM; rate = AL_VOCAL_MORPHER_DEFAULT_RATE; } public: property float phonemeACoarseTuning { get { return phonemeACoarseTuning; } set { phonemeACoarseTuning =RANGE(AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING, value, AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING); } } property float phonemeBCoarseTuning { get { return phonemeBCoarseTuning; } set { phonemeBCoarseTuning =RANGE(AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING, value, AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING); } } property float rate { get { return rate; } set { rate =RANGE(AL_VOCAL_MORPHER_MIN_RATE, value, AL_VOCAL_MORPHER_MAX_RATE); } } void Apply() { } void Update() { } void Print() { } } class EFXPitchShift : EFXEffect { int coarse, fine; EFXReverb() { coarse = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE; fine = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE; } public: property float coarse { get { return coarse; } set { coarse =RANGE(AL_PITCH_SHIFTER_MIN_COARSE_TUNE, value, AL_PITCH_SHIFTER_MAX_COARSE_TUNE); } } property float fine { get { return fine; } set { fine =RANGE(AL_PITCH_SHIFTER_MIN_FINE_TUNE, value, AL_PITCH_SHIFTER_MAX_FINE_TUNE); } } void Apply() { } void Update() { } void Print() { } } class EFXRingMod : EFXEffect { float frequency, cutoff; EFXWaveForm3b waveform; EFXReverb() { frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; cutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; waveform = (EFXWaveForm3b) AL_RING_MODULATOR_DEFAULT_WAVEFORM; } public: property float frequency { get { return frequency; } set { frequency =RANGE(AL_RING_MODULATOR_MIN_FREQUENCY, value, AL_RING_MODULATOR_MAX_FREQUENCY); } } property float cutoff { get { return cutoff; } set { cutoff =RANGE(AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF, value, AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF); } } void Apply() { } void Update() { } void Print() { } } class EFXAutoWah : EFXEffect { float attack, release, resonance, gain; EFXReverb() { attack = AL_AUTOWAH_DEFAULT_ATTACK_TIME; release = AL_AUTOWAH_DEFAULT_RELEASE_TIME; resonance = AL_AUTOWAH_DEFAULT_RESONANCE; gain = AL_AUTOWAH_DEFAULT_PEAK_GAIN; } public: property float attack { get { return attack; } set { attack =RANGE(AL_AUTOWAH_MIN_ATTACK_TIME, value, AL_AUTOWAH_MAX_ATTACK_TIME); } } property float release { get { return release; } set { release =RANGE(AL_AUTOWAH_MIN_RELEASE_TIME, value, AL_AUTOWAH_MAX_RELEASE_TIME); } } property float resonance { get { return resonance; } set { resonance =RANGE(AL_AUTOWAH_MIN_RESONANCE, value, AL_AUTOWAH_MAX_RESONANCE); } } property float gain { get { return gain; } set { gain =RANGE(AL_AUTOWAH_MIN_PEAK_GAIN, value, AL_AUTOWAH_MAX_PEAK_GAIN); } } void Apply() { } void Update() { } void Print() { } } class EFXCompressor { bool on; EFXReverb() { on = (bool) AL_COMPRESSOR_DEFAULT_ONOFF; } public: void Apply() { } void Update() { } void Print() { } } class EFXEqualizer { float lowGain, lowCutoff, mid1Gain, mid1Center, mid1Width, mid2Gain, mid2Center, mid2Width, highGain, highCutoff; EFXReverb() { lowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN; lowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF; mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN; mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER; mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH; mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN; mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER; mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH; highGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN; highCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF; } public: property float lowGain { get { return lowGain; } set { lowGain =RANGE(AL_EQUALIZER_MIN_LOW_GAIN, value, AL_EQUALIZER_MAX_LOW_GAIN); } } property float lowCutoff { get { return lowCutoff; } set { lowCutoff =RANGE(AL_EQUALIZER_MIN_LOW_CUTOFF, value, AL_EQUALIZER_MAX_LOW_CUTOFF); } } property float mid1Gain { get { return mid1Gain; } set { mid1Gain =RANGE(AL_EQUALIZER_MIN_MID1_GAIN, value, AL_EQUALIZER_MAX_MID1_GAIN); } } property float mid1Center { get { return mid1Center; } set { mid1Center =RANGE(AL_EQUALIZER_MIN_MID1_CENTER, value, AL_EQUALIZER_MAX_MID1_CENTER); } } property float mid1Width { get { return mid1Width; } set { mid1Width =RANGE(AL_EQUALIZER_MIN_MID1_WIDTH, value, AL_EQUALIZER_MAX_MID1_WIDTH); } } property float mid2Gain { get { return mid2Gain; } set { mid2Gain =RANGE(AL_EQUALIZER_MIN_MID2_GAIN, value, AL_EQUALIZER_MAX_MID2_GAIN); } } property float mid2Center { get { return mid2Center; } set { mid2Center =RANGE(AL_EQUALIZER_MIN_MID2_CENTER, value, AL_EQUALIZER_MAX_MID2_CENTER); } } property float mid2Width { get { return mid2Width; } set { mid2Width =RANGE(AL_EQUALIZER_MIN_MID2_WIDTH, value, AL_EQUALIZER_MAX_MID2_WIDTH); } } property float highGain { get { return highGain; } set { highGain =RANGE(AL_EQUALIZER_MIN_HIGH_GAIN, value, AL_EQUALIZER_MAX_HIGH_GAIN); } } property float highCutoff { get { return highCutoff; } set { highCutoff =RANGE(AL_EQUALIZER_MIN_HIGH_CUTOFF, value, AL_EQUALIZER_MAX_HIGH_CUTOFF); } } void Apply() { } void Update() { } void Print() { } } class EFXFilter { } class EFX { EFXEffect effects; int version_major,version_minor,max_aux_sends,meters_per_unit; LPALGENEFFECTS alGenEffects; LPALDELETEEFFECTS alDeleteEffects; LPALISEFFECT alIsEffect; LPALEFFECTI alEffecti; LPALEFFECTIV alEffectiv; LPALEFFECTF alEffectf; LPALEFFECTFV alEffectfv; LPALGETEFFECTI alGetEffecti; LPALGETEFFECTIV alGetEffectiv; LPALGETEFFECTF alGetEffectf; LPALGETEFFECTFV alGetEffectfv; LPALGENFILTERS alGenFilters; LPALDELETEFILTERS alDeleteFilters; LPALISFILTER alIsFilter; LPALFILTERI alFilteri; LPALFILTERIV alFilteriv; LPALFILTERF alFilterf; LPALFILTERFV alFilterfv; LPALGETFILTERI alGetFilteri; LPALGETFILTERIV alGetFilteriv; LPALGETFILTERF alGetFilterf; LPALGETFILTERFV alGetFilterfv; LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots; LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots; LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot; LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti; LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv; LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf; LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv; LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti; LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv; LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf; LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv; bool Init() { bool hasEFX=false; ALCdevice *device; ALuint obj; int i; const ALenum effects[] = { AL_EFFECT_EAXREVERB, AL_EFFECT_REVERB, AL_EFFECT_CHORUS, AL_EFFECT_DISTORTION, AL_EFFECT_ECHO, AL_EFFECT_FLANGER, AL_EFFECT_FREQUENCY_SHIFTER, AL_EFFECT_VOCAL_MORPHER, AL_EFFECT_PITCH_SHIFTER, AL_EFFECT_RING_MODULATOR, AL_EFFECT_AUTOWAH, AL_EFFECT_COMPRESSOR, AL_EFFECT_EQUALIZER, AL_EFFECT_NULL }; char effectNames[] = "EAX Reverb,Reverb,Chorus,Distortion,Echo,Flanger,Frequency Shifter,Vocal Morpher,pitch Shifter,Ring Modulator,Autowah,Compressor,Equalizer,"; const ALenum filters[] = { AL_FILTER_LOWPASS, AL_FILTER_HIGHPASS, AL_FILTER_BANDPASS, AL_FILTER_NULL }; char filterNames[] = "Low-pass,High-pass,Band-pass,"; char *current; device = alcGetContextsDevice(alcGetCurrentContext()); if(alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_FALSE) { printf("EFX not available.\n"); return; } alcGetIntegerv(device, ALC_EFX_MAJOR_VERSION, 1, &version_major); alcGetIntegerv(device, ALC_EFX_MINOR_VERSION, 1, &version_minor); checkForErrors(); printf("EFX version: %d.%d\n", (int)version_major, (int)version_minor); alcGetIntegerv(device, ALC_MAX_AUXILIARY_SENDS, 1, &max_aux_sends); checkForErrors(); printf("Max auxiliary sends: %d\n", (int)max_aux_sends); hasEFX = alcIsExtensionPresent(null, ALC_EXT_EFX_NAME ); if ( hasEFX ) { printf( "EFX extension available: \n" ); alGenEffects = (LPALGENEFFECTS) alGetProcAddress( "alGenEffects" ); if ( alGenEffects == null ) hasEFX = false; alDeleteEffects = (LPALDELETEEFFECTS) alGetProcAddress( "alDeleteEffects" ); if ( alDeleteEffects == null ) hasEFX = false; alIsEffect = (LPALISEFFECT) alGetProcAddress( "alIsEffect" ); if ( alIsEffect == null ) hasEFX = false; alEffecti = (LPALEFFECTI) alGetProcAddress( "alEffecti" ); if ( alEffecti == null ) hasEFX = false; alEffectiv = (LPALEFFECTIV) alGetProcAddress( "alEffectiv" ); if ( alEffectiv == null ) hasEFX = false; alEffectf = (LPALEFFECTF) alGetProcAddress( "alEffectf" ); if ( alEffectf == null ) hasEFX = false; alEffectfv = (LPALEFFECTFV) alGetProcAddress( "alEffectfv" ); if ( alEffectfv == null ) hasEFX = false; alGetEffecti = (LPALGETEFFECTI) alGetProcAddress( "alGetEffecti" ); if ( alGetEffecti == null ) hasEFX = false; alGetEffectiv = (LPALGETEFFECTIV) alGetProcAddress( "alGetEffectiv" ); if ( alGetEffectiv == null ) hasEFX = false; alGetEffectf = (LPALGETEFFECTF) alGetProcAddress( "alGetEffectf" ); if ( alGetEffectf == null ) hasEFX = false; alGetEffectfv = (LPALGETEFFECTFV) alGetProcAddress( "alGetEffectfv" ); if ( alGetEffectfv == null ) hasEFX = false; alGenFilters = (LPALGENFILTERS) alGetProcAddress( "alGenFilters" ); if ( alGenFilters == null ) hasEFX = false; alDeleteFilters = (LPALDELETEFILTERS) alGetProcAddress( "alDeleteFilters" ); if ( alDeleteFilters == null ) hasEFX = false; alIsFilter = (LPALISFILTER) alGetProcAddress( "alIsFilter" ); if ( alIsFilter == null ) hasEFX = false; alFilteri = (LPALFILTERI) alGetProcAddress( "alFilteri" ); if ( alFilteri == null ) hasEFX = false; alFilteriv = (LPALFILTERIV) alGetProcAddress( "alFilteriv" ); if ( alFilteriv == null ) hasEFX = false; alFilterf = (LPALFILTERF) alGetProcAddress( "alFilterf" ); if ( alFilterf == null ) hasEFX = false; alFilterfv = (LPALFILTERFV) alGetProcAddress( "alFilterfv" ); if ( alFilterfv == null ) hasEFX = false; alGetFilteri = (LPALGETFILTERI) alGetProcAddress( "alGetFilteri" ); if ( alGetFilteri == null ) hasEFX = false; alGetFilteriv = (LPALGETFILTERIV) alGetProcAddress( "alGetFilteriv" ); if ( alGetFilteriv == null ) hasEFX = false; alGetFilterf = (LPALGETFILTERF) alGetProcAddress( "alGetFilterf" ); if ( alGetFilterf == null ) hasEFX = false; alGetFilterfv = (LPALGETFILTERFV) alGetProcAddress( "alGetFilterfv" ); if ( alGetFilterfv == null ) hasEFX = false; alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS) alGetProcAddress( "alGenAuxiliaryEffectSlots" ); if ( alGenAuxiliaryEffectSlots == null ) hasEFX = false; alDeleteAuxiliaryEffectSlots = (LPALDELETEAUXILIARYEFFECTSLOTS) alGetProcAddress( "alDeleteAuxiliaryEffectSlots" ); if ( alDeleteAuxiliaryEffectSlots == null ) hasEFX = false; alIsAuxiliaryEffectSlot = (LPALISAUXILIARYEFFECTSLOT) alGetProcAddress( "alIsAuxiliaryEffectSlot" ); if ( alIsAuxiliaryEffectSlot == null ) hasEFX = false; alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI) alGetProcAddress( "alAuxiliaryEffectSloti" ); if ( alAuxiliaryEffectSloti == null ) hasEFX = false; alAuxiliaryEffectSlotiv = (LPALAUXILIARYEFFECTSLOTIV) alGetProcAddress( "alAuxiliaryEffectSlotiv" ); if ( alAuxiliaryEffectSlotiv == null ) hasEFX = false; alAuxiliaryEffectSlotf = (LPALAUXILIARYEFFECTSLOTF) alGetProcAddress( "alAuxiliaryEffectSlotf" ); if ( alAuxiliaryEffectSlotf == null ) hasEFX = false; alAuxiliaryEffectSlotfv = (LPALAUXILIARYEFFECTSLOTFV) alGetProcAddress( "alAuxiliaryEffectSlotfv" ); if ( alAuxiliaryEffectSlotfv == null ) hasEFX = false; alGetAuxiliaryEffectSloti = (LPALGETAUXILIARYEFFECTSLOTI) alGetProcAddress( "alGetAuxiliaryEffectSloti" ); if ( alGetAuxiliaryEffectSloti == null ) hasEFX = false; alGetAuxiliaryEffectSlotiv = (LPALGETAUXILIARYEFFECTSLOTIV) alGetProcAddress( "alGetAuxiliaryEffectSlotiv" ); if ( alGetAuxiliaryEffectSlotiv == null ) hasEFX = false; alGetAuxiliaryEffectSlotf = (LPALGETAUXILIARYEFFECTSLOTF) alGetProcAddress( "alGetAuxiliaryEffectSlotf" ); if ( alGetAuxiliaryEffectSlotf == null ) hasEFX = false; alGetAuxiliaryEffectSlotfv = (LPALGETAUXILIARYEFFECTSLOTFV) alGetProcAddress( "alGetAuxiliaryEffectSlotfv" ); if ( alGetAuxiliaryEffectSlotfv == null ) hasEFX = false; } alGetError(); if ( !hasEFX ) { ALError( "Failed to retreive EFX extension functions.\n" ); return; } alGenFilters(1, &obj); checkForErrors(); current = filterNames; for(i = 0;filters[i] != AL_FILTER_NULL;i++) { char *next = strchr(current, ','); alFilteri(obj, AL_FILTER_TYPE, filters[i]); if(alGetError() == AL_NO_ERROR) current = next+1; else memmove(current, next+1, strlen(next)); } alDeleteFilters(1, &obj); checkForErrors(); printList("Supported filters", ',', filterNames); alGenEffects(1, &obj); checkForErrors(); current = effectNames; for(i = 0;effects[i] != AL_EFFECT_NULL;i++) { char *next = strchr(current, ','); alEffecti(obj, AL_EFFECT_TYPE, effects[i]); if(alGetError() == AL_NO_ERROR) current = next+1; else memmove(current, next+1, strlen(next)); } alDeleteEffects(1, &obj); checkForErrors(); printList("Supported effects", ',', effectNames); return hasEFX=true; } } class ALDeviceDescription : ListItem { String name; property String name { set { delete name; name = CopyString(value); } }; ~ALDeviceDescription() { delete name; } } class ALDeviceDescriptions : LinkList<ALDeviceDescription> { bool inList(char *fn) { for (a : this; contains(a.name, fn)) return true; return false; } ALDeviceDescription find(char *fn) { for (a : this; contains(a.name, fn)) return a; return null; } } // Simple Sound Manager class ALSoundManager { ALWaveForms waveforms { }; ALUREStreams streams { }; ALSounds sounds { }; ALCDeviceContexts deviceContexts { }; bool error,initialized,muted,hasOggExtension,hasEAX; float distance, gain, max_gain, min_gain, dopplerFactor, dopplerVelocity; int version_major, version_minor, refreshRate; // uint bufferClamp, sourceClamp; uint monoSources, stereoSources; ALDeviceDescriptions outputs { }; ALDeviceDescriptions inputs { }; Timer timer { this, delay=(1.0f/refreshRate); started=false; bool DelayExpired() { alureUpdate(); //printf( "alureUpdate()\n" ); ALError("Update: "); for ( s : sounds) s._BetweenFrames(); sounds.DeleteDone(); timer.delay = (1.0f/refreshRate); timer.Start(); return true; } }; // EAX 2.0 GUIDs EAXSet eaxSet; // EAXSet function, retrieved if EAX Extension is supported EAXGet eaxGet; // EAXGet function, retrieved if EAX Extension is supported EFX efx {}; // EFX function bindings SoundVector position, velocity, orientation; // ^orientation of the Listener. (first 3 elements are "at", second 3 are "up") // Also note that these should be units of '1'. //bufferClamp=MAX_AUDIO_BUFFERS; //sourceClamp=MAX_AUDIO_SOURCES; refreshRate=60; distance = 10000.0f; gain=1.0f; max_gain=1.0f; min_gain=0.0f; position = SoundVector { x=0.0f, y=0.0f, z=0.0f }; velocity = SoundVector { x=0.0f, y=0.0f, z=0.0f }; orientation = SoundVector { x=0.0f, y=0.0f, z=-1.0f, a=0.0f, b=1.0f, c=0.0f }; ALSoundManager() { this.timer.delay = (1.0f/refreshRate); this.timer.Start(); } ~ALSoundManager() { for (s : sounds) { s.Release(); } delete sounds; delete efx; deviceContexts.Free(); for(s : streams) s.Stop(); streams.Free(); delete waveforms; } inline void ClearError() { alGetError(); } ALCdevice *currentDevice() { return alcGetContextsDevice(alcGetCurrentContext()); } ALCcontext *currentContext() { return alcGetCurrentContext(); } // Forces initialization defaulting to software when available. // You would use this to support EFX on most contemporary sound devices. // The device context is returned, or null if none was initialized. ALCDeviceContext InitSoftware() { ALCDeviceContext alc { }; alc.Init("Generic Software",0); if ( !Init(alc) ) { delete alc; return null; } return alc; } ALCDeviceContext InitDirectSound() { ALCDeviceContext alc { }; alc.Init("DirectSound",0); if ( !Init(alc) ) { delete alc; return null; } return alc; } ALCDeviceContext InitContext( char * context ) { ALCDeviceContext alc { }; alc.Init(context,0); if ( !Init(alc) ) { delete alc; return null; } return alc; } // Initialize OpenAL and clear the error bit. bool Init( ALCDeviceContext alc ) { const char *str; if ( initialized ) return; if ( alc ) { deviceContexts.Insert(null, alc); } else { alc = ALCDeviceContext { }; alc.PickDefault(); deviceContexts.Insert(null, alc); } str = alcGetString(alc.device, ALC_DEVICE_SPECIFIER); printf( "OpenAL initialized: %s\n", str ); //unusedBuffers=bufferClamp; //unusedSources=sourceClamp; alGetError(); if ( alGetError() != AL_NO_ERROR ) { printf( "Init: Error initializing audio!\n" ); initialized=false; return false; } printf( "ALSound: Initializing.\n" ); { ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); alcGetIntegerv(alc ? alc.device : device, ALC_MONO_SOURCES, 1, &monoSources); alcGetIntegerv(alc ? alc.device : device, ALC_STEREO_SOURCES, 1, &stereoSources); } printf( "Detected %d hinted mono source%s, and %d hinted stereo source%s.\n", monoSources, monoSources != 1 ? "s" : "", stereoSources, stereoSources != 1 ? "s" : "" ); if ( alIsExtensionPresent( "AL_EXT_vorbis" ) != AL_TRUE ) { printf( "Ogg Vorbis extension not available! This is probably not Linux.\n" ); hasOggExtension = false; } else hasOggExtension = true; // Check for EAX 2.0 support and // Retrieves function entry addresses to API ARB extensions, in this case, // for the EAX extension. See Appendix 1 (Extensions) of // http://www.openal.org/openal_webstf/specs/OpenAL1-1Spec_html/al11spec7.html hasEAX = alIsExtensionPresent( "EAX2.0" ); if ( hasEAX ) { printf( "EAX 2.0 extension is available.\n" ); eaxSet = (EAXSet) alGetProcAddress( "EAXSet" ); if ( eaxSet == null ) hasEAX = false; eaxGet = (EAXGet) alGetProcAddress( "EAXGet" ); if ( eaxGet == null ) hasEAX = false; if ( !hasEAX ) ALError( "Failed to retreive EAX extension functions.\n" ); } if ( !efx.Init() ) { delete efx; efx=null; printf( "EFX did not initialize properly, and therefore is unavailable.\n" ); } DeviceInfo( ); alGetError(); return true; } ALSound Cue( char *filename, float pitch, float gain, bool looped, bool createSource ) { ALSound sound; int newid; if ( !filename ) return null; alGetError(); // if ( unusedBuffers <= 0 ) { printf( "ALSound:Cue() No more buffers available (%d used)\n", bufferClamp-unusedBuffers ); return null; } sound = ALSound { pitch=pitch, gain=gain, loop=(ALboolean) looped, name=CopyString(filename) }; sound.waveform=waveforms.findOrLoad(filename); sound.format=sound.waveform.sfinfo.format; sound.size=sound.waveform.sampleCount * sound.waveform.sfinfo.channels *2; sound.freq=(uint) sound.waveform.sfinfo.samplerate; //sound.loop = looped ? AL_LOOP : 0; sound.duration=(float) sound.waveform.sampleCount / (float) sound.freq; //sound.printInfo(); sound.source = ALSource { }; // sources.Insert(null, sound.source); //unusedSources--; alGenSources(1, &(sound.source.id)); if(ALError("ALSoundManager:Cue:alGenSources")) { delete sound; return null; } sound.source.bindSound(sound); sounds.Insert(null, sound); return sound; } ALSound CueAndPlay( char *filename, float pitch, float gain, bool looped, bool createSource ) { ALSound s = Cue( filename, pitch, gain, looped, createSource ); // printf( "Attempting to play %s\n", filename ); // if ( !s ) printf( "Sound was null, so it couldn't have been played.\n" ); // else { // printf ( "Playing sound '%s' buffer %d source %d\n", s.name, (int) s.buffer.id, (int) s.source.id ); if ( s ) s.Play(); return s; } ALUREStream AddStream( char *fn, ALSource source, bool loop, bool calcLength ) { ALUREStream stream { }; if ( !source ) { // Bind the buffer with the source. stream.source = ALSource { }; //unusedSources--; alGenSources(1, &(stream.source.id)); if(ALError("ALSoundManager:WAV:alGenSources")) { return stream; } stream.source.bindStream(stream); // Do another error check and return. if(ALError("ALSoundManager:AddStream:alSource")) { return stream; } } else stream.source=source; streams.Insert(null, stream); incref stream; stream.manager=this; stream.loop=loop; if ( !stream.LoadIntoSource(fn,stream.source,calcLength) ) { printf("ALSoundManager:AddStream:stream.Create() had an error.\n" ); return stream; } return stream; } void SetListenerValues() { alListenerfv(AL_POSITION, position.asFloat3() ); alListenerfv(AL_VELOCITY, velocity.asFloat3() ); alListenerfv(AL_ORIENTATION, orientation.asFloat6() ); } void SetGain( float f ) { gain=f; alListenerf( AL_GAIN, gain ); } // Detaches all sources from buffers. This is done before all sounds are discarded. void Clear() { } bool ResumeAll( void ) { int sourceAudioState = 0; alGetError(); for ( s : sounds) { // Are we currently playing the audio source? alGetSourcei( s.source.id, AL_SOURCE_STATE, &sourceAudioState ); if ( sourceAudioState == AL_PAUSED ) { alSourcePlay( s.source.id ); if ( ALError( "ALSoundManager:ResumeAll:alSourcePlay") ) return false; s.source.state=playing; } } muted=false; return true; } bool PauseAll() { int sourceAudioState = 0; alGetError(); for ( s : sounds ) { if ( s.Playing() ) { alGetSourcei( s.source.id, AL_SOURCE_STATE, &sourceAudioState ); if ( sourceAudioState != AL_PAUSED ) { alSourcePause( s.source.id ); if ( ALError( "ALSoundManager:PauseAll:alSourcePa
Private
[
?
]
Run code