/** * @brief Updates the group sounds. */ void sound_al_update (void) { int i, j; alGroup_t *g; ALfloat d, v; unsigned int t, f; t = SDL_GetTicks(); for (i=0; i<al_ngroups; i++) { g = &al_groups[i]; /* Handle fadeout. */ if (g->state != VOICE_FADEOUT) continue; /* Calculate fadeout. */ f = t - g->fade_timer; if (f < SOUND_FADEOUT) { d = 1. - (ALfloat) f / (ALfloat) SOUND_FADEOUT; v = d * svolume * g->volume; if (g->speed) v *= svolume_speed; soundLock(); for (j=0; j<g->nsources; j++) alSourcef( g->sources[j], AL_GAIN, v ); /* Check for errors. */ al_checkErr(); soundUnlock(); } /* Fadeout done. */ else { soundLock(); v = svolume * g->volume; if (g->speed) v *= svolume_speed; for (j=0; j<g->nsources; j++) { alSourceStop( g->sources[j] ); alSourcei( g->sources[j], AL_BUFFER, AL_NONE ); alSourcef( g->sources[j], AL_GAIN, v ); } /* Check for errors. */ al_checkErr(); soundUnlock(); /* Mark as done. */ g->state = VOICE_PLAYING; } } }
/** * @brief Updates the listener. */ int sound_al_updateListener( double dir, double px, double py, double vx, double vy ) { double c, s; ALfloat ori[6], pos[3], vel[3]; c = cos(dir); s = sin(dir); soundLock(); ori[0] = c; ori[1] = s; ori[2] = 0.; ori[3] = 0.; ori[4] = 0.; ori[5] = 1.; alListenerfv( AL_ORIENTATION, ori ); pos[0] = px; pos[1] = py; pos[2] = 0.; alListenerfv( AL_POSITION, pos ); vel[0] = vx; vel[1] = vy; vel[2] = 0.; alListenerfv( AL_VELOCITY, vel ); /* Check for errors. */ al_checkErr(); soundUnlock(); return 0; }
/** * @brief Frees the music. */ void music_al_exit (void) { /* Kill the thread. */ music_kill(); SDL_WaitThread( music_player, NULL ); soundLock(); /* Free the music. */ alDeleteBuffers( 2, music_buffer ); alDeleteSources( 1, &music_source ); /* Check for errors. */ al_checkErr(); soundUnlock(); /* Free the buffer. */ if (music_buf != NULL) free(music_buf); music_buf = NULL; /* Destroy the mutex. */ SDL_DestroyMutex( music_vorbis_lock ); SDL_DestroyMutex( music_state_lock ); SDL_DestroyCond( music_state_cond ); }
/** * @brief Plays a sound in a group. */ int sound_al_playGroup( int group, alSound *s, int once ) { int i, j; alGroup_t *g; ALint state; for (i=0; i<al_ngroups; i++) { /* Find group. */ if (al_groups[i].id != group) continue; g = &al_groups[i]; g->state = VOICE_PLAYING; soundLock(); for (j=0; j<g->nsources; j++) { alGetSourcei( g->sources[j], AL_SOURCE_STATE, &state ); /* No free ones, just smash the last one. */ if (j == g->nsources-1) { if (state != AL_STOPPED) { alSourceStop( g->sources[j] ); alSourcef( g->sources[j], AL_GAIN, svolume ); } } /* Ignore playing/paused. */ else if ((state == AL_PLAYING) || (state == AL_PAUSED)) continue; /* Attach buffer. */ alSourcei( g->sources[j], AL_BUFFER, s->u.al.buf ); /* Do not do positional sound. */ alSourcei( g->sources[j], AL_SOURCE_RELATIVE, AL_TRUE ); /* See if should loop. */ alSourcei( g->sources[j], AL_LOOPING, (once) ? AL_FALSE : AL_TRUE ); /* Start playing. */ alSourcePlay( g->sources[j] ); /* Check for errors. */ al_checkErr(); soundUnlock(); return 0; } soundUnlock(); WARN("Group '%d' has no free sounds.", group ); /* Group matched but not found. */ break; } if (i>=al_ngroups) WARN("Group '%d' not found.", group); return -1; }
/** * @brief Creates a sound environment. */ int sound_al_env( SoundEnv_t env, double param ) { int i; ALuint s; ALfloat f; soundLock(); switch (env) { case SOUND_ENV_NORMAL: /* Set global parameters. */ alSpeedOfSound( 3433. ); if (al_info.efx == AL_TRUE) { /* Disconnect the effect. */ nalAuxiliaryEffectSloti( efx_directSlot, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL ); /* Set per-source parameters. */ for (i=0; i<source_ntotal; i++) { s = source_total[i]; alSourcef( s, AL_AIR_ABSORPTION_FACTOR, 0. ); } } break; case SOUND_ENV_NEBULA: f = param / 1000.; /* Set global parameters. */ alSpeedOfSound( 3433./(1. + f*2.) ); if (al_info.efx == AL_TRUE) { if (al_info.efx_reverb == AL_TRUE) { /* Tweak the reverb. */ nalEffectf( efx_reverb, AL_REVERB_DECAY_TIME, 10. ); nalEffectf( efx_reverb, AL_REVERB_DECAY_HFRATIO, 0.5 ); /* Connect the effect. */ nalAuxiliaryEffectSloti( efx_directSlot, AL_EFFECTSLOT_EFFECT, efx_reverb ); } /* Set per-source parameters. */ for (i=0; i<source_ntotal; i++) { s = source_total[i]; alSourcef( s, AL_AIR_ABSORPTION_FACTOR, 3.*f ); } } break; } /* Check for errors. */ al_checkErr(); soundUnlock(); return 0; }
/** * @brief Resumes all sounds. */ void sound_al_resume (void) { soundLock(); al_resumev( source_ntotal, source_total ); /* Check for errors. */ al_checkErr(); soundUnlock(); }
/** * @brief Updates the voice. * * @param v Voice to update. */ void sound_al_updateVoice( alVoice *v ) { ALint state; /* Invalid source, mark to delete. */ if (v->u.al.source == 0) { v->state = VOICE_DESTROY; return; } soundLock(); /* Get status. */ alGetSourcei( v->u.al.source, AL_SOURCE_STATE, &state ); if (state == AL_STOPPED) { /* Remove buffer so it doesn't start up again if resume is called. */ alSourcei( v->u.al.source, AL_BUFFER, AL_NONE ); /* Check for errors. */ al_checkErr(); soundUnlock(); /* Put source back on the list. */ source_stack[source_nstack] = v->u.al.source; source_nstack++; v->u.al.source = 0; /* Mark as stopped - erased next iteration. */ v->state = VOICE_STOPPED; return; } /* Set up properties. */ alSourcef( v->u.al.source, AL_GAIN, svolume ); alSourcefv( v->u.al.source, AL_POSITION, v->u.al.pos ); alSourcefv( v->u.al.source, AL_VELOCITY, v->u.al.vel ); /* Check for errors. */ al_checkErr(); soundUnlock(); }
/** * @brief Set the playing speed. */ void sound_al_setSpeed( double s ) { int i; soundLock(); for (i=0; i<source_nall; i++) alSourcef( source_all[i], AL_PITCH, s ); /* Check for errors. */ al_checkErr(); soundUnlock(); }
/** * @brief Loads the sound. * * @param snd Sound to load. * @param filename Name of the file to load into sound. */ int sound_al_load( alSound *snd, const char *filename ) { int ret; SDL_RWops *rw; OggVorbis_File vf; ALint freq, bits, channels, size; /* get the file data buffer from packfile */ rw = ndata_rwops( filename ); /* Check to see if it's an OGG. */ if (ov_test_callbacks( rw, &vf, NULL, 0, sound_al_ovcall_noclose )==0) { ret = sound_al_loadOgg( snd, &vf ); } /* Otherwise try WAV. */ else { /* Destroy the partially loaded vorbisfile. */ ov_clear(&vf); /* Try to load Wav. */ ret = sound_al_loadWav( snd, rw ); } /* Close RWops. */ SDL_RWclose(rw); /* Failed to load. */ if (ret != 0) { WARN("Failed to load sound file '%s'.", filename); return ret; } soundLock(); /* Get the length of the sound. */ alGetBufferi( snd->u.al.buf, AL_FREQUENCY, &freq ); alGetBufferi( snd->u.al.buf, AL_BITS, &bits ); alGetBufferi( snd->u.al.buf, AL_CHANNELS, &channels ); alGetBufferi( snd->u.al.buf, AL_SIZE, &size ); if ((freq==0) || (bits==0) || (channels==0)) { WARN("Something went wrong when loading sound file '%s'.", filename); snd->length = 0; } else snd->length = (double)size / (double)(freq * (bits/8) * channels); /* Check for errors. */ al_checkErr(); soundUnlock(); return 0; }
/** * @brief Stops playing sound. */ void sound_al_stop( alVoice* voice ) { soundLock(); if (voice->u.al.source != 0) alSourceStop( voice->u.al.source ); /* Check for errors. */ al_checkErr(); soundUnlock(); }
/** * @brief Plays a voice. */ static int al_playVoice( alVoice *v, alSound *s, ALfloat px, ALfloat py, ALfloat vx, ALfloat vy, ALint relative ) { /* Must be below the limit. */ if (sound_speed > SOUND_SPEED_PLAY_LIMIT) return 0; /* Set up the source and buffer. */ v->u.al.source = sound_al_getSource(); if (v->u.al.source == 0) return -1; v->u.al.buffer = s->u.al.buf; soundLock(); /* Attach buffer. */ alSourcei( v->u.al.source, AL_BUFFER, v->u.al.buffer ); /* Enable positional sound. */ alSourcei( v->u.al.source, AL_SOURCE_RELATIVE, relative ); /* Update position. */ v->u.al.pos[0] = px; v->u.al.pos[1] = py; v->u.al.pos[2] = 0.; v->u.al.vel[0] = vx; v->u.al.vel[1] = vy; v->u.al.vel[2] = 0.; /* Set up properties. */ alSourcef( v->u.al.source, AL_GAIN, svolume*svolume_speed ); alSourcefv( v->u.al.source, AL_POSITION, v->u.al.pos ); alSourcefv( v->u.al.source, AL_VELOCITY, v->u.al.vel ); /* Defaults just in case. */ alSourcei( v->u.al.source, AL_LOOPING, AL_FALSE ); /* Start playing. */ alSourcePlay( v->u.al.source ); /* Check for errors. */ al_checkErr(); soundUnlock(); return 0; }
/** * @brief Initializes the OpenAL music subsystem. */ int music_al_init (void) { ALfloat v[] = { 0., 0., 0. }; /* Create threading mechanisms. */ music_state_cond = SDL_CreateCond(); music_state_lock = SDL_CreateMutex(); music_vorbis_lock = SDL_CreateMutex(); music_vorbis.rw = NULL; /* indication it's not loaded */ /* Create the buffer. */ music_bufSize = conf.al_bufsize * 1024; music_buf = malloc( music_bufSize ); soundLock(); /* music_source created in sound_al_init. */ /* Generate buffers and sources. */ alGenBuffers( 2, music_buffer ); /* Set up OpenAL properties. */ alSourcef( music_source, AL_GAIN, music_vol ); alSourcei( music_source, AL_SOURCE_RELATIVE, AL_TRUE ); alSourcefv( music_source, AL_POSITION, v ); alSourcefv( music_source, AL_VELOCITY, v ); /* Check for errors. */ al_checkErr(); /* Set state to none. */ music_state = 0; soundUnlock(); /* * Start up thread and have it inform us when it already reaches the main loop. */ musicLock(); music_state = MUSIC_STATE_STARTUP; music_player = SDL_CreateThread( music_thread, NULL ); SDL_CondWait( music_state_cond, music_state_lock ); musicUnlock(); return 0; }
/** * @brief Sets the volume. */ int music_al_volume( double vol ) { soundLock(); music_vol = vol; /* only needed if playing */ if (music_al_isPlaying()) { alSourcef( music_source, AL_GAIN, vol ); /* Check for errors. */ al_checkErr(); } soundUnlock(); return 0; }
/** * @brief Plays a voice. */ static int al_playVoice( alVoice *v, alSound *s, ALfloat px, ALfloat py, ALfloat vx, ALfloat vy, ALint relative ) { /* Set up the source and buffer. */ v->u.al.source = sound_al_getSource(); if (v->u.al.source == 0) return -1; v->u.al.buffer = s->u.al.buf; soundLock(); /* Attach buffer. */ alSourcei( v->u.al.source, AL_BUFFER, v->u.al.buffer ); /* Enable positional sound. */ alSourcei( v->u.al.source, AL_SOURCE_RELATIVE, relative ); /* Update position. */ v->u.al.pos[0] = px; v->u.al.pos[1] = py; v->u.al.pos[2] = 0.; v->u.al.vel[0] = vx; v->u.al.vel[1] = vy; v->u.al.vel[2] = 0.; /* Set up properties. */ alSourcef( v->u.al.source, AL_GAIN, svolume ); alSourcefv( v->u.al.source, AL_POSITION, v->u.al.pos ); alSourcefv( v->u.al.source, AL_VELOCITY, v->u.al.vel ); /* Start playing. */ alSourcePlay( v->u.al.source ); /* Check for errors. */ al_checkErr(); soundUnlock(); return 0; }
/** * @brief Set the playing speed. */ void sound_al_setSpeed( double s ) { int i, j; alGroup_t *g; soundLock(); sound_speed = s; /* Set the speed. */ /* Do all the groupless. */ for (i=0; i<source_ntotal; i++) alSourcef( source_total[i], AL_PITCH, s ); /* Do specific groups. */ for (i=0; i<al_ngroups; i++) { g = &al_groups[i]; if (!g->speed) continue; for (j=0; j<g->nsources; j++) alSourcef( g->sources[j], AL_PITCH, s ); } /* Check for errors. */ al_checkErr(); soundUnlock(); }
/** * @brief Sets the volume. */ int music_al_volume( double vol ) { soundLock(); music_vol_lin = vol; if (vol > 0.) /* Floor of -48 dB (0.00390625 amplitude) */ music_vol = 1 / pow(2, (1 - vol) * 8 ); else music_vol = 0.; /* only needed if playing */ if (music_al_isPlaying()) { alSourcef( music_source, AL_GAIN, music_vol ); /* Check for errors. */ al_checkErr(); } soundUnlock(); return 0; }
/** * @brief Creates a sound environment. */ int sound_al_env( SoundEnv_t env, double param ) { int i; ALuint s; ALfloat f; soundLock(); switch (env) { case SOUND_ENV_NORMAL: /* Set global parameters. */ alSpeedOfSound( 3433. ); if (al_info.efx == AL_TRUE) { /* Disconnect the effect. */ nalAuxiliaryEffectSloti( efx_directSlot, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL ); /* Set per-source parameters. */ for (i=0; i<source_ntotal; i++) { s = source_total[i]; alSourcef( s, AL_AIR_ABSORPTION_FACTOR, 0. ); } } break; case SOUND_ENV_NEBULA: f = param / 1000.; /* Set global parameters. */ alSpeedOfSound( 3433./(1. + f*2.) ); if (al_info.efx == AL_TRUE) { if (al_info.efx_reverb == AL_TRUE) { /* Tweak the reverb. */ nalEffectf( efx_reverb, AL_REVERB_DECAY_TIME, 10. ); nalEffectf( efx_reverb, AL_REVERB_DECAY_HFRATIO, 0.5 ); /* Connect the effect. */ nalAuxiliaryEffectSloti( efx_directSlot, AL_EFFECTSLOT_EFFECT, efx_reverb ); } /* Set per-source parameters. */ for (i=0; i<source_ntotal; i++) { s = source_total[i]; /* Value is from 0. (normal) to 10.. * It represents the attenuation per meter. In this case it decreases by * 0.05*AB_FACTOR dB/meter where AB_FACTOR is the air absoprtion factor. * In our case each pixel represents 5 meters. */ alSourcef( s, AL_AIR_ABSORPTION_FACTOR, 3.*f ); } } break; } /* Check for errors. */ al_checkErr(); soundUnlock(); return 0; }
/** * @brief The music thread. * * @param unused Unused. */ static int music_thread( void* unused ) { (void)unused; int ret; int active; /* active buffer */ ALint state; ALuint removed[2]; ALenum value; music_state_t cur_state; ALfloat gain; int fadein_start = 0; uint32_t fade, fade_timer = 0; while (1) { /* Handle states. */ musicLock(); /* Handle new command. */ switch (music_command) { case MUSIC_CMD_KILL: if (music_state != MUSIC_STATE_IDLE) music_state = MUSIC_STATE_STOPPING; else { music_state = MUSIC_STATE_DEAD; } /* Does not clear command. */ break; case MUSIC_CMD_STOP: /* Notify of stopped. */ if (music_state == MUSIC_STATE_IDLE) SDL_CondBroadcast( music_state_cond ); else music_state = MUSIC_STATE_STOPPING; break; case MUSIC_CMD_PLAY: /* Set appropriate state. */ if (music_state == MUSIC_STATE_PAUSING) music_state = MUSIC_STATE_RESUMING; else if (music_state == MUSIC_STATE_FADEIN) fade_timer = SDL_GetTicks() - MUSIC_FADEIN_DELAY; else music_state = MUSIC_STATE_LOADING; /* Disable fadein. */ fadein_start = 0; /* Clear command. */ music_command = MUSIC_CMD_NONE; SDL_CondBroadcast( music_state_cond ); break; case MUSIC_CMD_FADEOUT: /* Notify of stopped. */ if (music_state != MUSIC_STATE_IDLE) { music_state = MUSIC_STATE_FADEOUT; /* Set timer. */ fade_timer = SDL_GetTicks(); } /* Clear command. */ music_command = MUSIC_CMD_NONE; SDL_CondBroadcast( music_state_cond ); break; case MUSIC_CMD_FADEIN: if ((music_state == MUSIC_STATE_FADEIN) || (music_state == MUSIC_STATE_PLAYING)) SDL_CondBroadcast( music_state_cond ); else { music_state = MUSIC_STATE_LOADING; /* Set timer. */ fade_timer = SDL_GetTicks(); fadein_start = 1; } /* Clear command. */ music_command = MUSIC_CMD_NONE; break; case MUSIC_CMD_PAUSE: if (music_state == MUSIC_STATE_PAUSED) SDL_CondBroadcast( music_state_cond ); else if ((music_state == MUSIC_STATE_PLAYING) || (music_state == MUSIC_STATE_FADEIN)) music_state = MUSIC_STATE_PAUSING; music_command = MUSIC_CMD_NONE; break; case MUSIC_CMD_NONE: break; } cur_state = music_state; musicUnlock(); /* * Main processing loop. */ switch (cur_state) { /* * Basically send a message that thread is up and running. */ case MUSIC_STATE_STARTUP: musicLock(); music_state = MUSIC_STATE_IDLE; SDL_CondBroadcast( music_state_cond ); musicUnlock(); break; /* * We died. */ case MUSIC_STATE_DEAD: return 0; break; /* * Delays at the end. */ case MUSIC_STATE_PAUSED: case MUSIC_STATE_IDLE: break; /* * Resumes the paused song. */ case MUSIC_STATE_RESUMING: soundLock(); alSourcePlay( music_source ); alSourcef( music_source, AL_GAIN, music_vol ); /* Check for errors. */ al_checkErr(); soundUnlock(); musicLock(); music_state = MUSIC_STATE_PLAYING; SDL_CondBroadcast( music_state_cond ); musicUnlock(); break; /* * Pause the song. */ case MUSIC_STATE_PAUSING: soundLock(); alSourcePause( music_source ); /* Check for errors. */ al_checkErr(); soundUnlock(); musicLock(); music_state = MUSIC_STATE_PAUSED; SDL_CondBroadcast( music_state_cond ); musicUnlock(); break; /* * Stop song setting to IDLE. */ case MUSIC_STATE_STOPPING: soundLock(); /* Stop and remove buffers. */ alSourceStop( music_source ); alGetSourcei( music_source, AL_BUFFERS_PROCESSED, &value ); if (value > 0) alSourceUnqueueBuffers( music_source, value, removed ); /* Clear timer. */ fade_timer = 0; /* Reset volume. */ alSourcef( music_source, AL_GAIN, music_vol ); soundUnlock(); musicLock(); music_state = MUSIC_STATE_IDLE; SDL_CondBroadcast( music_state_cond ); if (!music_forced) music_rechoose(); musicUnlock(); break; /* * Load the song. */ case MUSIC_STATE_LOADING: /* Load buffer and start playing. */ active = 0; /* load first buffer */ ret = stream_loadBuffer( music_buffer[active] ); soundLock(); alSourceQueueBuffers( music_source, 1, &music_buffer[active] ); /* Special case NULL file or error. */ if (ret < 0) { soundUnlock(); /* Force state to stopped. */ musicLock(); music_state = MUSIC_STATE_IDLE; SDL_CondBroadcast( music_state_cond ); if (!music_forced) music_rechoose(); musicUnlock(); break; } /* Force volume level. */ alSourcef( music_source, AL_GAIN, (fadein_start) ? 0. : music_vol ); /* Start playing. */ alSourcePlay( music_source ); /* Check for errors. */ al_checkErr(); soundUnlock(); /* Special case of a very short song. */ if (ret > 1) { active = -1; musicLock(); if (fadein_start) music_state = MUSIC_STATE_FADEIN; else music_state = MUSIC_STATE_PLAYING; SDL_CondBroadcast( music_state_cond ); musicUnlock(); break; } /* Load second buffer. */ active = 1; ret = stream_loadBuffer( music_buffer[active] ); if (ret < 0) { active = -1; } else { soundLock(); alSourceQueueBuffers( music_source, 1, &music_buffer[active] ); /* Check for errors. */ al_checkErr(); soundUnlock(); active = 1 - active; } musicLock(); if (fadein_start) music_state = MUSIC_STATE_FADEIN; else music_state = MUSIC_STATE_PLAYING; SDL_CondBroadcast( music_state_cond ); musicUnlock(); break; /* * Fades in the music. */ case MUSIC_STATE_FADEOUT: case MUSIC_STATE_FADEIN: /* See if must still fade. */ fade = SDL_GetTicks() - fade_timer; if (cur_state == MUSIC_STATE_FADEIN) { if (fade < MUSIC_FADEIN_DELAY) { gain = (ALfloat)fade / (ALfloat)MUSIC_FADEIN_DELAY; soundLock(); alSourcef( music_source, AL_GAIN, gain*music_vol ); /* Check for errors. */ al_checkErr(); soundUnlock(); } /* No need to fade anymore. */ else { /* Set volume to normal level. */ soundLock(); alSourcef( music_source, AL_GAIN, music_vol ); /* Check for errors. */ al_checkErr(); soundUnlock(); /* Change state to playing. */ musicLock(); music_state = MUSIC_STATE_PLAYING; musicUnlock(); } } else if (cur_state == MUSIC_STATE_FADEOUT) { if (fade < MUSIC_FADEOUT_DELAY) { gain = 1. - (ALfloat)fade / (ALfloat)MUSIC_FADEOUT_DELAY; soundLock(); alSourcef( music_source, AL_GAIN, gain*music_vol ); /* Check for errors. */ al_checkErr(); soundUnlock(); } else { /* Music should stop. */ musicLock(); music_state = MUSIC_STATE_STOPPING; musicUnlock(); break; } } /* Purpose fallthrough. */ /* * Play the song if needed. */ case MUSIC_STATE_PLAYING: /* Special case where file has ended. */ if (active < 0) { soundLock(); alGetSourcei( music_source, AL_SOURCE_STATE, &state ); if (state == AL_STOPPED) { alGetSourcei( music_source, AL_BUFFERS_PROCESSED, &value ); if (value > 0) alSourceUnqueueBuffers( music_source, value, removed ); soundUnlock(); musicLock(); music_state = MUSIC_STATE_IDLE; if (!music_forced) music_rechoose(); musicUnlock(); break; } soundUnlock(); break; } soundLock(); /* See if needs another buffer set. */ alGetSourcei( music_source, AL_BUFFERS_PROCESSED, &state ); if (state > 0) { /* refill active buffer */ alSourceUnqueueBuffers( music_source, 1, removed ); ret = stream_loadBuffer( music_buffer[active] ); if (ret < 0) { active = -1; } else { alSourceQueueBuffers( music_source, 1, &music_buffer[active] ); active = 1 - active; } } /* Check for errors. */ al_checkErr(); soundUnlock(); } /* * Global thread delay. */ SDL_Delay(0); } return 0; }
/** * @brief Enables the OpenAL EFX extension. * * @return 0 on success. */ static int al_enableEFX (void) { /* Get general information. */ alcGetIntegerv( al_device, ALC_MAX_AUXILIARY_SENDS, 1, &al_info.efx_auxSends ); alcGetIntegerv( al_device, ALC_EFX_MAJOR_VERSION, 1, &al_info.efx_major ); alcGetIntegerv( al_device, ALC_EFX_MINOR_VERSION, 1, &al_info.efx_minor ); /* Get function pointers. */ nalGenAuxiliaryEffectSlots = alGetProcAddress( "alGenAuxiliaryEffectSlots" ); nalDeleteAuxiliaryEffectSlots = alGetProcAddress( "alDeleteAuxiliaryEffectSlots" ); nalIsAuxiliaryEffectSlot = alGetProcAddress( "alIsAuxiliaryEffectSlot" ); nalAuxiliaryEffectSloti = alGetProcAddress( "alAuxiliaryEffectSloti" ); nalAuxiliaryEffectSlotiv = alGetProcAddress( "alAuxiliaryEffectSlotiv" ); nalAuxiliaryEffectSlotf = alGetProcAddress( "alAuxiliaryEffectSlotf" ); nalAuxiliaryEffectSlotfv = alGetProcAddress( "alAuxiliaryEffectSlotfv" ); nalGetAuxiliaryEffectSloti = alGetProcAddress( "alGetAuxiliaryEffectSloti" ); nalGetAuxiliaryEffectSlotiv = alGetProcAddress( "alGetAuxiliaryEffectSlotiv" ); nalGetAuxiliaryEffectSlotf = alGetProcAddress( "alGetAuxiliaryEffectSlotf" ); nalGetAuxiliaryEffectSlotfv = alGetProcAddress( "alGetAuxiliaryEffectSlotfv" ); nalGenFilters = alGetProcAddress( "alGenFilters" ); nalDeleteFilters = alGetProcAddress( "alDeleteFilters" ); nalFilteri = alGetProcAddress( "alFilteri" ); nalFilteriv = alGetProcAddress( "alFilteriv" ); nalFilterf = alGetProcAddress( "alFilterf" ); nalFilterfv = alGetProcAddress( "alFilterfv" ); nalGenEffects = alGetProcAddress( "alGenEffects" ); nalDeleteEffects = alGetProcAddress( "alDeleteEffects" ); nalEffecti = alGetProcAddress( "alEffecti" ); nalEffectiv = alGetProcAddress( "alEffectiv" ); nalEffectf = alGetProcAddress( "alEffectf" ); nalEffectfv = alGetProcAddress( "alEffectfv" ); if (!nalGenAuxiliaryEffectSlots || !nalDeleteAuxiliaryEffectSlots || !nalIsAuxiliaryEffectSlot || !nalAuxiliaryEffectSloti || !nalAuxiliaryEffectSlotiv || !nalAuxiliaryEffectSlotf || !nalAuxiliaryEffectSlotfv || !nalGetAuxiliaryEffectSloti || !nalGetAuxiliaryEffectSlotiv || !nalGetAuxiliaryEffectSlotf || !nalGetAuxiliaryEffectSlotfv || !nalGenFilters || !nalDeleteFilters || !nalFilteri || !nalFilteriv || !nalFilterf || !nalFilterfv || !nalGenEffects || !nalDeleteEffects || !nalEffecti || !nalEffectiv || !nalEffectf || !nalEffectfv) { DEBUG("OpenAL EFX functions not found, disabling EFX."); al_info.efx = AL_FALSE; return -1; } /* Create auxiliary slot. */ nalGenAuxiliaryEffectSlots( 1, &efx_directSlot ); /* Create reverb effect. */ nalGenEffects( 1, &efx_reverb ); nalEffecti( efx_reverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB ); if(alGetError() != AL_NO_ERROR) { DEBUG("OpenAL Reverb not found, disabling."); al_info.efx_reverb = AL_FALSE; nalDeleteEffects( 1, &efx_reverb ); } else { al_info.efx_reverb = AL_TRUE; /* Set Reverb parameters. */ /*nalEffectf( efx_reverb, AL_REVERB_DECAY_TIME, 15. );*/ } /* Create echo effect. */ nalGenEffects( 1, &efx_echo ); nalEffecti( efx_echo, AL_EFFECT_TYPE, AL_EFFECT_ECHO ); if(alGetError() != AL_NO_ERROR) { DEBUG("OpenAL Echo not found, disabling."); al_info.efx_echo = AL_FALSE; nalDeleteEffects( 1, &efx_echo ); } else { al_info.efx_echo = AL_TRUE; /* Set Echo parameters. */ nalEffectf( efx_echo, AL_ECHO_DELAY, 0.207 ); } /* Set up the listener. */ alListenerf( AL_METERS_PER_UNIT, 5. ); /* Check for errors. */ al_checkErr(); return 0; }
/** * @brief Initializes the sound subsystem. * * @return 0 on success. */ int sound_al_init (void) { int ret; const ALchar* dev; ALuint s; ALint freq; ALint attribs[4] = { 0, 0, 0, 0 }; /* Default values. */ ret = 0; /* we'll need a mutex */ sound_lock = SDL_CreateMutex(); soundLock(); /* Get the sound device. */ dev = alcGetString( NULL, ALC_DEFAULT_DEVICE_SPECIFIER ); /* opening the default device */ al_device = alcOpenDevice(NULL); if (al_device == NULL) { WARN("Unable to open default sound device"); ret = -1; goto snderr_dev; } /* Query EFX extension. */ if (conf.al_efx) { al_info.efx = alcIsExtensionPresent( al_device, "ALC_EXT_EFX" ); if (al_info.efx == AL_TRUE) { attribs[0] = ALC_MAX_AUXILIARY_SENDS; attribs[1] = 4; } } else al_info.efx = AL_FALSE; /* Create the OpenAL context */ al_context = alcCreateContext( al_device, attribs ); if (sound_lock == NULL) { WARN("Unable to create OpenAL context"); ret = -2; goto snderr_ctx; } /* Clear the errors */ alGetError(); /* Set active context */ if (alcMakeContextCurrent( al_context )==AL_FALSE) { WARN("Failure to set default context"); ret = -4; goto snderr_act; } /* Get context information. */ alcGetIntegerv( al_device, ALC_FREQUENCY, sizeof(freq), &freq ); /* Try to enable EFX. */ if (al_info.efx == AL_TRUE) al_enableEFX(); else { al_info.efx_reverb = AL_FALSE; al_info.efx_echo = AL_FALSE; } /* Allocate source for music. */ alGenSources( 1, &music_source ); /* Check for errors. */ al_checkErr(); /* Start allocating the sources - music has already taken his */ source_nstack = 0; source_mstack = 0; while (source_nstack < SOUND_MAX_SOURCES) { if (source_mstack < source_nstack+1) { /* allocate more memory */ source_mstack += 32; source_stack = realloc( source_stack, sizeof(ALuint) * source_mstack ); } alGenSources( 1, &s ); source_stack[source_nstack] = s; /* Distance model defaults. */ alSourcef( s, AL_MAX_DISTANCE, 5000. ); alSourcef( s, AL_ROLLOFF_FACTOR, 1. ); alSourcef( s, AL_REFERENCE_DISTANCE, 500. ); /* Set the filter. */ if (al_info.efx == AL_TRUE) alSource3i( s, AL_AUXILIARY_SEND_FILTER, efx_directSlot, 0, AL_FILTER_NULL ); /* Check for error. */ if (alGetError() == AL_NO_ERROR) source_nstack++; else break; } /* Reduce ram usage. */ source_mstack = source_nstack; source_stack = realloc( source_stack, sizeof(ALuint) * source_mstack ); /* Copy allocated sources to total stack. */ source_ntotal = source_mstack; source_total = malloc( sizeof(ALuint) * source_mstack ); memcpy( source_total, source_stack, sizeof(ALuint) * source_mstack ); /* Copy allocated sources to all stack. */ source_nall = source_mstack; source_all = malloc( sizeof(ALuint) * source_mstack ); memcpy( source_all, source_stack, sizeof(ALuint) * source_mstack ); /* Set up how sound works. */ alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED ); alDopplerFactor( 1. ); sound_al_env( SOUND_ENV_NORMAL, 0. ); /* Check for errors. */ al_checkErr(); /* we can unlock now */ soundUnlock(); /* debug magic */ DEBUG("OpenAL started: %d Hz", freq); DEBUG("Renderer: %s", alGetString(AL_RENDERER)); if (al_info.efx == AL_FALSE) DEBUG("Version: %s without EFX", alGetString(AL_VERSION)); else DEBUG("Version: %s with EFX %d.%d", alGetString(AL_VERSION), al_info.efx_major, al_info.efx_minor); DEBUG(); return 0; /* * error handling */ snderr_act: alcDestroyContext( al_context ); snderr_ctx: al_context = NULL; alcCloseDevice( al_device ); snderr_dev: al_device = NULL; soundUnlock(); SDL_DestroyMutex( sound_lock ); sound_lock = NULL; return ret; }
/** * @brief Initializes the sound subsystem. * * @return 0 on success. */ int sound_al_init (void) { int ret; ALuint s; ALint freq; ALint attribs[4] = { 0, 0, 0, 0 }; /* Default values. */ ret = 0; /* we'll need a mutex */ sound_lock = SDL_CreateMutex(); soundLock(); /* opening the default device */ al_device = alcOpenDevice(NULL); if (al_device == NULL) { WARN(_("Unable to open default sound device")); ret = -1; goto snderr_dev; } /* Query EFX extension. */ if (conf.al_efx) { al_info.efx = alcIsExtensionPresent( al_device, "ALC_EXT_EFX" ); if (al_info.efx == AL_TRUE) { attribs[0] = ALC_MAX_AUXILIARY_SENDS; attribs[1] = 4; } } else al_info.efx = AL_FALSE; /* Create the OpenAL context */ al_context = alcCreateContext( al_device, attribs ); if (al_context == NULL) { WARN(_("Unable to create OpenAL context")); ret = -2; goto snderr_ctx; } /* Clear the errors */ alGetError(); /* Set active context */ if (alcMakeContextCurrent( al_context )==AL_FALSE) { WARN(_("Failure to set default context")); ret = -4; goto snderr_act; } /* Get context information. */ alcGetIntegerv( al_device, ALC_FREQUENCY, sizeof(freq), &freq ); /* Try to enable EFX. */ if (al_info.efx == AL_TRUE) al_enableEFX(); else { al_info.efx_reverb = AL_FALSE; al_info.efx_echo = AL_FALSE; } /* Allocate source for music. */ alGenSources( 1, &music_source ); /* Check for errors. */ al_checkErr(); /* Start allocating the sources - music has already taken his */ source_nstack = 0; source_mstack = 0; while (source_nstack < conf.snd_voices) { if (source_mstack < source_nstack+1) { /* allocate more memory */ if (source_mstack == 0) source_mstack = conf.snd_voices; else source_mstack *= 2; source_stack = realloc( source_stack, sizeof(ALuint) * source_mstack ); } alGenSources( 1, &s ); source_stack[source_nstack] = s; /* How OpenAL distance model works: * * Clamped: * gain = distance_function( CLAMP( AL_REFERENCE_DISTANCE, AL_MAX_DISTANCE, distance ) ); * * Distance functions: * AL_REFERENCE_DISTANCE * * Inverse = ------------------------------------------------------------------------------ * AL_REFERENCE_DISTANCE + AL_ROLLOFF_FACTOR ( distance - AL_REFERENCE_DISTANCE ) * * 1 - AL_ROLLOFF_FACTOR ( distance - AL_REFERENCE_DISTANCE ) * * Linear = ---------------------------------------------------------- * AL_MAX_DISTANCE - AL_REFERENCE_DISTANCE * * / distance \ -AL_ROLLOFF_FACTOR * * Exponential = | --------------------- | * \ AL_REFERENCE_DISTANCE / * * * Some values: * * model falloff reference 100 1000 5000 10000 * linear 1 500 1.000 0.947 0.526 0.000 * inverse 1 500 1.000 0.500 0.100 0.050 * exponent 1 500 1.000 0.500 0.100 0.050 * inverse 0.5 500 1.000 0.667 0.182 0.095 * exponent 0.5 500 1.000 0.707 0.316 0.223 * inverse 2 500 1.000 0.333 0.052 0.026 * exponent 2 500 1.000 0.250 0.010 0.003 */ alSourcef( s, AL_REFERENCE_DISTANCE, 500. ); /* Close distance to clamp at (doesn't get louder). */ alSourcef( s, AL_MAX_DISTANCE, 25000. ); /* Max distance to clamp at (doesn't get quieter). */ alSourcef( s, AL_ROLLOFF_FACTOR, 1. ); /* Determines how it drops off. */ /* Set the filter. */ if (al_info.efx == AL_TRUE) alSource3i( s, AL_AUXILIARY_SEND_FILTER, efx_directSlot, 0, AL_FILTER_NULL ); /* Check for error. */ if (alGetError() == AL_NO_ERROR) source_nstack++; else break; } /* Reduce ram usage. */ source_mstack = source_nstack; source_stack = realloc( source_stack, sizeof(ALuint) * source_mstack ); /* Copy allocated sources to total stack. */ source_ntotal = source_mstack; source_total = malloc( sizeof(ALuint) * source_mstack ); memcpy( source_total, source_stack, sizeof(ALuint) * source_mstack ); /* Copy allocated sources to all stack. */ source_nall = source_mstack; source_all = malloc( sizeof(ALuint) * source_mstack ); memcpy( source_all, source_stack, sizeof(ALuint) * source_mstack ); /* Set up how sound works. */ alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED ); /* Clamping is fundamental so it doesn't sound like crap. */ alDopplerFactor( 1. ); sound_al_env( SOUND_ENV_NORMAL, 0. ); /* Check for errors. */ al_checkErr(); /* we can unlock now */ soundUnlock(); /* debug magic */ DEBUG(_("OpenAL started: %d Hz"), freq); DEBUG(_("Renderer: %s"), alGetString(AL_RENDERER)); if (al_info.efx == AL_FALSE) DEBUG(_("Version: %s without EFX"), alGetString(AL_VERSION)); else DEBUG(_("Version: %s with EFX %d.%d"), alGetString(AL_VERSION), al_info.efx_major, al_info.efx_minor); DEBUG(""); return ret; /* * error handling */ snderr_act: alcDestroyContext( al_context ); snderr_ctx: al_context = NULL; alcCloseDevice( al_device ); snderr_dev: al_device = NULL; soundUnlock(); SDL_DestroyMutex( sound_lock ); sound_lock = NULL; return ret; }