misc/libopenalbridge/commands.c
author unc0rr
Sun, 02 Dec 2012 01:25:11 +0400
changeset 8178 8bd087478b48
parent 3697 d5b30d6373fc
permissions -rw-r--r--
Fix QSettings problems: - Reopen file in ReadOnly mode if it was open in ReadWrite mode and is being read. This is needed for stupid QSettings which opens file in ReadWrite mode just to call readAll() on it. - Implement setSize(0)

/*
 *  commands.c
 *  Hedgewars
 *
 *  Created by Vittorio on 13/06/10.
 *  Copyright 2010 __MyCompanyName__. All rights reserved.
 *
 */

#include "commands.h"
#include "wrappers.h"

ALfloat old_gain;
extern ALuint *Sources;
extern ALuint cache_size, cache_index, sources_number;
extern ALboolean instances_number;
extern al_sound_t *the_sounds;

void openal_pausesound (uint32_t index) {
    if (openal_ready() == AL_TRUE && index < cache_size)
        alSourcePause(Sources[the_sounds[index].source_index]);
}


void openal_stopsound (uint32_t index) {
    if (openal_ready() == AL_TRUE && index < cache_size)
        alSourceStop(Sources[the_sounds[index].source_index]);
}


void openal_playsound (unsigned int index) {
    ALboolean needsSource = AL_TRUE;
    ALfloat SourcePosition[] = { 0.0, 0.0, 0.0 };
    ALfloat SourceVelocity[] = { 0.0, 0.0, 0.0 };
    ALint state;
    int i, j;

    if (openal_ready() == AL_TRUE && index < cache_size) {
        // check if sound has already a source
        if (the_sounds[index].source_index != -1) {
            // it has a source, check it's not playing
            alGetSourcei(Sources[the_sounds[index].source_index], AL_SOURCE_STATE, &state);
            if (state != AL_PLAYING && state != AL_PAUSED) {
                // it is not being played, so we can use it safely
	            needsSource = AL_FALSE;
            }
            // else it is being played, so we have to allocate a new source for this buffer
        }

        if (needsSource) {
#ifdef DEBUG
            fprintf(stderr,"(Bridge Debug) - looking for a source for sound %d\n", index);
#endif
            for (i = 0; i < sources_number; i++) {
                // let's iterate on Sources until we find a source that is not playing
                alGetSourcei(Sources[i], AL_SOURCE_STATE, &state);
                if (state != AL_PLAYING && state != AL_PAUSED) {
                    // let's iterate on the_sounds until we find the sound using that source
                    for (j = 0; j < cache_size; j++) {
                        if (the_sounds[j].source_index == i) {
                            the_sounds[j].source_index = -1;
                            break;
                        }
                    }
                    // here we know that no-one is using that source so we can use it
                    break;
                }
            }

            if (i == sources_number) {
                // this means all sources are busy
            }

            // set source properties that it will use when it's in playback
            alSourcei (Sources[i], AL_BUFFER,   the_sounds[index].buffer);
            alSourcef (Sources[i], AL_PITCH,    1.0f);
            alSourcef (Sources[i], AL_GAIN,     1.0f);
            alSourcefv(Sources[i], AL_POSITION, SourcePosition);
            alSourcefv(Sources[i], AL_VELOCITY, SourceVelocity);
            alSourcei (Sources[i], AL_LOOPING,  0);

            if (AL_NO_ERROR != alGetError()) {
                fprintf(stderr,"(Bridge ERROR) - failed to set Source properties\n");
                return;
            }
            the_sounds[index].source_index = i;
        }

        alSourcePlay(Sources[the_sounds[index].source_index]);

        if (AL_NO_ERROR != alGetError()) {
            fprintf(stderr,"(Bridge Warning) - failed to play sound %d\n", index);
            return;
        }
    }
}

void openal_toggleloop (uint32_t index) {
    ALint loop;

    if (openal_ready() == AL_TRUE && index < cache_size) {
        alGetSourcei (Sources[the_sounds[index].source_index], AL_LOOPING, &loop);
        alSourcei (Sources[the_sounds[index].source_index], AL_LOOPING, !((uint8_t) loop) & 0x00000001);
    }
}


void openal_setvolume (uint32_t index, float gain) {
    if (openal_ready() == AL_TRUE && index < cache_size)
        alSourcef (Sources[the_sounds[index].source_index], AL_GAIN, gain);
}


void openal_setglobalvolume (float gain) {
    if (openal_ready() == AL_TRUE)
        alListenerf (AL_GAIN, gain);
}

void openal_togglemute () {
    ALfloat gain;

    if (openal_ready() == AL_TRUE) {
        alGetListenerf (AL_GAIN, &gain);
        if (gain > 0) {
            old_gain = gain;
            gain = 0;
        } else
            gain = old_gain;

        alListenerf (AL_GAIN, gain);
    }
}

// Fade in or out by calling a helper thread
void openal_fade (uint32_t index, uint16_t quantity, al_fade_t direction) {
#ifndef _WIN32
    pthread_t thread;
#else
    HANDLE Thread;
#endif
    fade_t *fade;

    if (openal_ready() == AL_TRUE && index < cache_size) {
        fade = (fade_t*) Malloc(sizeof(fade_t));
        fade->index = index;
        fade->quantity = quantity;
        fade->type = direction;

#ifndef _WIN32
        pthread_create(&thread, NULL, (void *)helper_fade, (void *)fade);
        pthread_detach(thread);
#else
        Thread = (HANDLE) _beginthread((void *)helper_fade, 0, (void *)fade);
#endif
    }
}

void openal_setposition (uint32_t index, float x, float y, float z) {
    if (openal_ready() == AL_TRUE && index < cache_size)
        alSource3f(Sources[the_sounds[index].source_index], AL_POSITION, x, y, z);;
}

void helper_fade(void *tmp) {
    ALfloat gain;
    ALfloat target_gain;
    fade_t *fade;
    uint32_t index;
    uint16_t quantity;
    al_fade_t type;

    fade = tmp;
    index = fade->index;
    quantity = fade->quantity;
    type = fade->type;
    free (fade);

    if (type == AL_FADE_IN) {
#ifdef DEBUG
        fprintf(stderr,"(Bridge Info) - Fade-in in progress [index %d quantity %d]", index, quantity);
#endif

        // save the volume desired after the fade
        alGetSourcef(Sources[the_sounds[index].source_index], AL_GAIN, &target_gain);
        if (target_gain > 1.0f || target_gain <= 0.0f)
            target_gain = 1.0f;

        for (gain = 0.0f ; gain <= target_gain; gain += (float) quantity/10000) {
#ifdef TRACE
            fprintf(stderr,"(Bridge Debug) - Fade-in set gain to %f\n", gain);
#endif
            alSourcef(Sources[the_sounds[index].source_index], AL_GAIN, gain);
            usleep(10000);
        }
    } else {
        alGetSourcef(Sources[the_sounds[index].source_index], AL_GAIN, &target_gain);

        for (gain = target_gain; gain >= 0.00f; gain -= (float) quantity/10000) {
#ifdef TRACE
            fprintf(stderr,"(Bridge Debug) - Fade-out set gain to %f\n", gain);
#endif
            alSourcef(Sources[the_sounds[index].source_index], AL_GAIN, gain);
            usleep(10000);
        }

        if (AL_NO_ERROR != alGetError())
            fprintf(stderr,"(Bridge Warning) - Failed to set fade-out effect\n");

        // stop that sound and reset its volume
        alSourceStop (Sources[the_sounds[index].source_index]);
        alSourcef (Sources[the_sounds[index].source_index], AL_GAIN, target_gain);
    }

    if (AL_NO_ERROR != alGetError())
        fprintf(stderr,"(Bridge Warning) - Failed to set fade effect\n");

#ifndef _WIN32
    pthread_exit(NULL);
#else
    _endthread();
#endif
}