openalbridge/openalbridge.c
author koda
Wed, 14 Oct 2009 22:12:02 +0000
changeset 2443 fececcbc2189
parent 2437 10e4b5fc0d93
child 2444 ace11b7d8eab
permissions -rw-r--r--
Smaxx patch for fixing all sound related issues on any system

/*
 * OpenAL Bridge - a simple portable library for OpenAL interface
 * Copyright (c) 2009 Vittorio Giovara <vittorio.giovara@gmail.com>,
 *                    Mario Liebisch <mario.liebisch+hw@googlemail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; version 2 of the License
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

#include "openalbridge.h"


char *prog;

/*Buffers hold sound data*/
ALuint *Buffers;
/*index for Sources and Buffers*/
ALuint globalindex, globalsize, increment;

//null vector
const ALfloat NV[] = {0.0f, 0.0f, 0.0f};
//listener orientation
const ALfloat LO[] = {0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f};

SSound_t aSounds[MAX_SOUNDS];
int iNumSounds = 0;
char oalbReady = 0;

ALCcontext *context;
ALCdevice *device;
ALuint sources[MAX_SOURCES];





/**
 * const char oalb_init (const char* programname, const char usehardware) 
 *
 *  ARGUMENTS
 * programname [const char*]: name of the program invoking OpenAL
 * usehardware [const char] : flag to enable audio hardware acceleration
 *  DESCRIPTION
 *
 *  RETURN
 * 1 success
 * 2 error
 */

char oalb_init (const char* programname, const char usehardware) {                
        prog = (char *) programname;
        
        if (oalbReady == AL_TRUE) {
                errno = EPERM;                
                err_ret("(%s) WARN - OpenAL already initialized", prog);
                return AL_FALSE;
        }
        
#ifdef _WIN32
        /* Hardware acceleration is broken on some windows card*/
        if (usehardware != 0)
                device = alcOpenDevice(NULL);
        else
        {
                device = alcOpenDevice("Generic Software");
                if(!device)
                {
                        err_msg("(%s) WARN - Failed to open software device", prog);
                        device = alcOpenDevice(NULL);
                }
        }
#else
        /*always hardware for UNIX systems*/
        device = alcOpenDevice(NULL);
#endif
        
        if (device == NULL) {
                errno = ENODEV;                
                err_ret("(%s) WARN - Failed to open sound device", prog);
                return AL_FALSE;
        }
        
        err_msg("(%s) INFO - Using OpenAL device: %s", prog, alcGetString(device, ALC_DEVICE_SPECIFIER));
        
        context = alcCreateContext(device, NULL);
        alcMakeContextCurrent(context);
        
        if (AlGetError("(%s) WARN - Failed to create a new contex") != AL_TRUE)
                return AL_FALSE;
        
        
        /*set the listener gain, position (on xyz axes), velocity (one value for each axe) and orientation*/
        alListenerf (AL_GAIN,        1.0f);
        alListenerfv(AL_POSITION,    NV);
        alListenerfv(AL_VELOCITY,    NV);
        alListenerfv(AL_ORIENTATION, LO);
        
        alcProcessContext(context);
        
        if (AlGetError("(%s) WARN - Failed to set Listener properties") != AL_TRUE)
                return AL_FALSE;
        
        alGenSources(MAX_SOURCES, sources);
        
        oalbReady = AL_TRUE;
        
        alGetError();  /* clear any AL errors beforehand */
        return AL_TRUE;
}


/**
 * void oalb_close(void) 
 *
 *  ARGUMENTS
 * -
 *  DESCRIPTION
 *
 *  RETURN
 * -
 */

void oalb_close(void) {
        /*Stop all sounds, deallocate all memory and close OpenAL */
        int i;
        
        if (oalbReady == 0) {
                errno = EPERM;
                err_ret("(%s) WARN - OpenAL not initialized", prog);
                return;
        }
        
        for(i = 0; i < iNumSounds; i++) {
                SSound_stop(&aSounds[i]);
                SSound_close(&aSounds[i]);
        }
        
        alSourceStopv (MAX_SOURCES, sources);
        alDeleteSources (MAX_SOURCES, sources);
        
        alcMakeContextCurrent(NULL);
        alcDestroyContext(context);
        alcCloseDevice(device);
        
        oalbReady = 0;
        
        return;
}

char oalb_ready(void) {
        return oalbReady;
}

/**
 * const int32_t oalb_loadfile (const char *filename) 
 *
 *  ARGUMENTS
 * -
 *  DESCRIPTION
 *
 *  RETURN
 * -
 */

int32_t oalb_loadfile (const char *filename) {
        int i;
        
        if (oalbReady == 0) {
                errno = EPERM;                
                err_ret("(%s) WARN - OpenAL not initialized", prog);
                return -1;
        }
        
        if(iNumSounds == MAX_SOUNDS) {
                err_msg("(%s) WARN - Maximum number of sound samples reached", prog);
                return -3;
        }
        
        
        for(i = 0; i < iNumSounds; i++)
                if(strcmp(aSounds[i].Filename, filename) == 0)
                        return i;
        
        if(SSound_load(&aSounds[iNumSounds], filename))
                return iNumSounds++;
        else
                return -2;
        
}

/*    
 ALboolean openal_toggleloop (uint32_t index){
 /*Set or unset looping mode
 ALint loop;
 
 if (oalbReady == AL_FALSE) {
 errno = EPERM;                
 err_ret("(%s) WARN - OpenAL not initialized", prog);
 return AL_FALSE;
 }
 
 if (index >= globalsize) {
 errno = EINVAL;
 err_ret("(%s) ERROR - Index out of bounds (got %d, max %d)", prog, index, globalindex);
 return AL_FALSE;
 }
 
 alGetSourcei (Sources[index], AL_LOOPING, &loop);
 alSourcei (Sources[index], AL_LOOPING, !((uint8_t) loop) & 0x00000001);
 if (AlGetError("(%s) ERROR - Failed to get or set loop property") != AL_TRUE)
 return AL_FALSE;
 
 alGetError();  /* clear any AL errors beforehand 
 
 return AL_TRUE;
 }
 */

void oalb_setvolume (const uint32_t iIndex,  const char cPercentage) {
        if (oalbReady == 0) {
                errno = EPERM;                
                err_ret("(%s) WARN - OpenAL not initialized", prog);
                return;
        }
        
        /*Set volume for sound number index*/
        if(iIndex < 0 || iIndex >= iNumSounds) {
                errno = EINVAL;
                err_ret("(%s) ERROR - Index out of bounds (got %d, max %d)", prog, index, globalindex);
                return;
        }
        
        if(cPercentage > 100)
                SSound_volume(&aSounds[iIndex], 1.0f);
        else
                SSound_volume(&aSounds[iIndex], cPercentage / 100.0f);
        
        if (AlGetError2("(%s) ERROR -  Failed to set volume for sound %d\n", iIndex) != AL_TRUE)
                return;
        
        alGetError();  /* clear any AL errors beforehand */
        
        return;
}


void oalb_setglobalvolume (const char cPercentage) {
        if (oalbReady == 0) {
                errno = EPERM;                
                err_ret("(%s) WARN - OpenAL not initialized", prog);
                return;
        }
        
        /*Set volume for all sounds*/		
        if(cPercentage > 100)
                alListenerf (AL_GAIN, 1.0f);
        else
                alListenerf (AL_GAIN, cPercentage / 100.0f);
        
        if (AlGetError("(%s) ERROR -  Failed to set global volume") != AL_TRUE)
                return;
        
        alGetError();  /* clear any AL errors beforehand */
        
        return;
}

/*     
 ALboolean openal_togglemute () {
 /*Mute or unmute sound
 ALfloat mute;
 
 if (oalbReady == AL_FALSE) {
 errno = EPERM;                
 err_ret("(%s) WARN - OpenAL not initialized", prog);
 return AL_FALSE;
 }
 
 alGetListenerf (AL_GAIN, &mute);
 if (mute > 0) 
 mute = 0;
 else
 mute = 1.0;
 alListenerf (AL_GAIN, mute);
 if (AlGetError("(%s) ERROR -  Failed to set mute property") != AL_TRUE)
 return AL_FALSE;
 
 alGetError();  /* clear any AL errors beforehand 
 
 return AL_TRUE;
 }
 
 
 ALboolean openal_fade (uint32_t index, uint16_t quantity, ALboolean direction) {
 /*Fade in or out by calling a helper thread
 #ifndef _WIN32
 pthread_t thread;
 #else
 HANDLE Thread;
 DWORD threadID;
 #endif
 fade_t *fade;
 
 if (oalbReady == AL_FALSE) {
 errno = EPERM;                
 err_ret("(%s) WARN - OpenAL not initialized", prog);
 return AL_FALSE;
 }
 
 fade = (fade_t*) Malloc(sizeof(fade_t));
 fade->index = index;
 fade->quantity = quantity;
 
 if (index >= globalsize) {
 errno = EINVAL;
 err_ret("(%s) ERROR - Index out of bounds (got %d, max %d)", prog, index, globalindex);
 return AL_FALSE;
 }
 
 switch (direction) {
 case FADE_IN:
 #ifndef _WIN32
 pthread_create(&thread, NULL, helper_fadein, (void*) fade);
 #else
 Thread = _beginthread(&helper_fadein, 0, (void*) fade);
 #endif
 break;
 case FADE_OUT:
 #ifndef _WIN32
 pthread_create(&thread, NULL, helper_fadeout, (void*) fade);
 #else
 Thread = _beginthread(&helper_fadeout, 0, (void*) fade);
 #endif	
 break;
 default:
 errno = EINVAL;
 err_ret("(%s) ERROR - Unknown direction for fading", prog, index, globalindex);
 free(fade);
 return AL_FALSE;
 break;
 }
 
 #ifndef _WIN32
 pthread_detach(thread);
 #endif
 
 alGetError();  /* clear any AL errors beforehand 
 
 return AL_TRUE;
 }
 
 
 ALboolean openal_fadeout (uint32_t index, uint16_t quantity) {
 /*wrapper for fadeout
 return openal_fade(index, quantity, FADE_OUT);
 }
 
 
 ALboolean openal_fadein (uint32_t index, uint16_t quantity) {
 /*wrapper for fadein
 return openal_fade(index, quantity, FADE_IN);
 }
 
 
 ALboolean openal_setposition (uint32_t index, float x, float y, float z) {
 if (oalbReady == AL_FALSE) {
 errno = EPERM;                
 err_ret("(%s) WARN - OpenAL not initialized", prog);
 return AL_FALSE;
 }
 
 if (index >= globalsize) {
 errno = EINVAL;
 err_ret("(%s) ERROR - Index out of bounds (got %d, max %d)", prog, index, globalindex);
 return AL_FALSE;
 }
 
 alSource3f(Sources[index], AL_POSITION, x, y, z);
 if (AlGetError2("(%s) ERROR - Failed to set position for sound %d)", index) != AL_TRUE)
 return AL_FALSE;
 
 return AL_TRUE;
 }
 
 */

void oalb_playsound (const uint32_t iIndex, const char bLoop) {
        if (oalbReady == AL_FALSE) {
                errno = EPERM;                
                err_ret("(%s) WARN - OpenAL not initialized", prog);
                return;
        }
        
        /*Play sound number index*/
        if(iIndex < 0 || iIndex >= iNumSounds) {
                errno = EINVAL;
                err_ret("(%s) ERROR - Index (%d) out of bounds", prog, iIndex);
                return;
        }
        SSound_play(&aSounds[iIndex], bLoop);
        
        
        
        alGetError();  /* clear any AL errors beforehand */
        
        return;
}


void oalb_pausesound (const uint32_t iIndex) {
        if (oalbReady == AL_FALSE) {
                errno = EPERM;                
                err_ret("(%s) WARN - OpenAL not initialized", prog);
                return;
        }
        
        /*Pause sound number index*/
        if(iIndex < 0 || iIndex >= iNumSounds) {
                errno = EINVAL;
                err_ret("(%s) ERROR - Index (%d) out of bounds", prog, iIndex);
                return;
        }
        SSound_pause(&aSounds[iIndex]);
        
        if (AlGetError2("(%s) ERROR - Failed to pause sound %d)", iIndex) != AL_TRUE)
                return;
        
        return;
}


void oalb_stopsound (const uint32_t iIndex) {
        if (oalbReady == AL_FALSE) {
                errno = EPERM;                
                err_ret("(%s) WARN - OpenAL not initialized", prog);
                return;
        }
        
        /*Stop sound number index*/
        if(iIndex < 0 || iIndex >= iNumSounds) {
                errno = EINVAL;
                err_ret("(%s) ERROR - Index (%d) out of bounds", prog, iIndex);
                return;
        }
        SSound_stop(&aSounds[iIndex]);
        
        if (AlGetError2("(%s) ERROR - Failed to stop sound %d)", iIndex) != AL_TRUE)
                return;
        
        alGetError();  /* clear any AL errors beforehand */
        
        return;
}


/*SSOUND STUFF HERE*/

char SSound_load (SSound_t* pSound, const char* cFilename) {
        uint32_t magic;
        ALenum format;
        ALsizei bitsize, freq;
        char *data;
        FILE* fp;
        
        snprintf(pSound->Filename, 256, "%s", cFilename);
        pSound->source = -1;
        alGenBuffers(1, &pSound->Buffer);
        
        if(alGetError() != AL_NO_ERROR) {
                fprintf(stderr, "CSound: Couldn't create buffer.\n");
                return 0;
        }
        
        fp = fopen(pSound->Filename, "rb");
        
        if(!fp) {
                fprintf(stderr, "CSound: Couldn't open file for reading.\n");
                return 0;
        }
        
        if(fread(&magic, sizeof(uint32_t), 1, fp) < 1)
        {
                fclose(fp);
                fprintf(stderr, "CSound: Couldn't read file header.\n");
                return 0;
        }
        fclose(fp);
        
        switch (ENDIAN_BIG_32(magic)) {
                case OGG_FILE_FORMAT:
                        load_oggvorbis (pSound->Filename, &format, &data, &bitsize, &freq);
                        break;
                case WAV_FILE_FORMAT:
                        load_wavpcm (pSound->Filename, &format, &data, &bitsize, &freq);
                        break;
                default:
                        errno = EINVAL;
                        err_ret ("(%s) ERROR - File format (%08X) not supported", prog, ENDIAN_BIG_32(magic));
                        return 0;
                        break;
        }
        
        alBufferData(pSound->Buffer, format, data, bitsize, freq);
        if(alGetError() != AL_NO_ERROR)
        {
                fprintf(stderr, "CSound: Couldn't write buffer data.\n");
                return 0;
        }
        free(data);
        
        return 1;
}

void SSound_close(SSound_t* pSound)
{
        SSound_stop(pSound);
        alDeleteBuffers(1, &pSound->Buffer);
}

void SSound_play(SSound_t* pSound, const char bLoop) {
        int i;
        
        if(pSound->source == -1) // need a new source
        {
                int i;
                for(i = 0; i < MAX_SOURCES; i++)
                {
                        ALint state;
                        alGetSourcei(sources[i], AL_SOURCE_STATE, &state);
                        if(state != AL_PLAYING && state != AL_PAUSED)
                        {
#ifdef DEBUG
                                printf("using source %d (state 0x%x) for buffer.\n", i, state);
#endif
                                alSourceStop(sources[pSound->source]);
                                alGetError();
                                break;
                        }
                }
                if(i == MAX_SOURCES) // no available source found; skip
                {
#ifdef DEBUG
                        printf("no source to play buffer %d!\n", i);
#endif
                        return;
                }
                pSound->source = i;
        }
        else // reuse already playing source
        {
                alSourceStop(sources[pSound->source]);
        }
        alSourcei (sources[pSound->source], AL_BUFFER, pSound->Buffer);
        alSourcef (sources[pSound->source], AL_PITCH,            1.0f);
        alSourcef (sources[pSound->source], AL_GAIN,             1.0f);
        alSourcefv(sources[pSound->source], AL_POSITION, NV          );
        alSourcefv(sources[pSound->source], AL_VELOCITY, NV          );
        alSourcei (sources[pSound->source], AL_LOOPING,  bLoop       );
        alSourcePlay(sources[pSound->source]);
        
        if((i = alGetError()) != AL_NO_ERROR)
        {
                fprintf(stderr, "CSound: SourcePlay error 0x%4x in source %d\n", i, pSound->source);
        }
#ifdef DEBUG
        fprintf(stderr, "play %s%s [%d]\n", pSound->Filename, bLoop ? " forever" : " once", pSound->source);
#endif
}

void SSound_pause(const SSound_t* pSound) {
        if(pSound->source == -1) // not playing
                return;
        alSourcePause(sources[pSound->source]);
#ifdef DEBUG
        fprintf(stderr, "pause %s\n", pSound->Filename);
#endif
}

void SSound_continue(const SSound_t* pSound) {
        if(pSound->source == -1) // not playing
                return;
        alSourcePlay(sources[pSound->source]);
#ifdef DEBUG
        fprintf(stderr, "pause %s\n", pSound->Filename);
#endif
}

void SSound_stop(SSound_t* pSound) {
        if(pSound->source == -1) // not playing
                return;
        alSourceStop(sources[pSound->source]);
        pSound->source = -1;
#ifdef DEBUG
        fprintf(stderr, "stop %s\n", pSound->Filename);
#endif
}

void SSound_volume(const SSound_t* pSound, const float fPercentage) {
        if(pSound->source == -1) // not playing
                return;
        alSourcef(sources[pSound->source], AL_GAIN, fPercentage);
}