/** * @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 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; }
void CCoreAudioAE::Shutdown() { CSingleLock engineLock(m_engineLock); Stop(); Deinitialize(); /* free the streams */ CSingleLock streamLock(m_streamLock); while (!m_streams.empty()) { CCoreAudioAEStream *s = m_streams.front(); m_sounds.pop_front(); delete s; } /* free the sounds */ CSingleLock soundLock(m_soundLock); while (!m_sounds.empty()) { CCoreAudioAESound *s = m_sounds.front(); m_sounds.pop_front(); delete s; } delete HAL; HAL = NULL; }
/** * @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 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 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 Frees the source. */ void sound_al_free( alSound *snd ) { soundLock(); /* free the stuff */ alDeleteBuffers( 1, &snd->u.al.buf ); soundUnlock(); }
/** * @brief Cleans up after the sound subsytem. */ void sound_al_exit (void) { int i; soundLock(); /* Free groups. */ for (i=0; i<al_ngroups; i++) { if (al_groups[i].sources != NULL) { free(al_groups[i].sources); } al_groups[i].sources = NULL; al_groups[i].nsources = 0; } if (al_groups != NULL) free(al_groups); al_groups = NULL; al_ngroups = 0; /* Free stacks. */ if (source_all != NULL) { alSourceStopv( source_nall, source_all ); alDeleteSources( source_nall, source_all ); free(source_all); } source_all = NULL; source_nall = 0; if (source_total) free(source_total); source_total = NULL; source_ntotal = 0; if (source_stack != NULL) free(source_stack); source_stack = NULL; source_nstack = 0; source_mstack = 0; /* Clean up EFX stuff. */ if (al_info.efx == AL_TRUE) { nalDeleteAuxiliaryEffectSlots( 1, &efx_directSlot ); if (al_info.efx_reverb == AL_TRUE) nalDeleteEffects( 1, &efx_reverb ); if (al_info.efx_echo == AL_TRUE) nalDeleteEffects( 1, &efx_echo ); } /* Clean up global stuff. */ if (al_context) { alcMakeContextCurrent(NULL); alcDestroyContext( al_context ); } if (al_device) alcCloseDevice( al_device ); soundUnlock(); SDL_DestroyMutex( sound_lock ); }
void ResourceManager::unloadAll() { sf::Lock texLock( texMutex ); sf::Lock soundLock( soundMutex ); sf::Lock fontLock( fontMutex ); textures.clear(); soundBuffers.clear(); fonts.clear(); }
/** * @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 Resumes a group. */ void sound_al_resumeGroup( int group ) { alGroup_t *g; g = sound_al_getGroup( group ); if (g == NULL) return; soundLock(); al_resumev( g->nsources, g->sources ); soundUnlock(); }
/** * @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 Sets all the sounds volume to vol */ int sound_al_volume( double vol ) { int i; svolume = (ALfloat) vol; soundLock(); for (i=0; i<source_nall; i++) alSourcef( source_all[i], AL_GAIN, svolume ); soundUnlock(); return 0; }
/** * @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 Sets all the sounds volume to vol */ int sound_al_volume( double vol ) { int i; svolume_lin = vol; if (vol > 0.) /* Floor of -48 dB (0.00390625 amplitude) */ svolume = (ALfloat) 1 / pow(2, (1 - vol) * 8); else svolume = 0.; soundLock(); for (i=0; i<source_nall; i++) alSourcef( source_all[i], AL_GAIN, svolume ); 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 ) { /* 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 Loads a wav file from the rw if possible. * * @note Closes the rw. * * @param snd Sound to load wav into. * @param rw Data for the wave. */ static int sound_al_loadWav( alSound *snd, SDL_RWops *rw ) { SDL_AudioSpec wav_spec; Uint32 wav_length; Uint8 *wav_buffer; ALenum format; SDL_RWseek( rw, 0, SEEK_SET ); /* Load WAV. */ if (SDL_LoadWAV_RW( rw, 0, &wav_spec, &wav_buffer, &wav_length) == NULL) { WARN(_("SDL_LoadWav_RW failed: %s"), SDL_GetError()); return -1; } /* Handle format. */ switch (wav_spec.format) { case AUDIO_U8: case AUDIO_S8: format = (wav_spec.channels==1) ? AL_FORMAT_MONO8 : AL_FORMAT_STEREO8; break; case AUDIO_U16LSB: case AUDIO_S16LSB: format = (wav_spec.channels==1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; break; case AUDIO_U16MSB: case AUDIO_S16MSB: WARN( _("Big endian WAVs unsupported!") ); return -1; default: WARN( _("Invalid WAV format!") ); return -1; } /* Load into openal. */ soundLock(); /* Create new buffer. */ alGenBuffers( 1, &snd->u.al.buf ); /* Put into the buffer. */ alBufferData( snd->u.al.buf, format, wav_buffer, wav_length, wav_spec.freq ); soundUnlock(); /* Clean up. */ free( wav_buffer ); return 0; }
/** * @brief Loads an ogg file from a tested format if possible. * * @param snd Sound to load ogg into. * @param vf Vorbisfile containing the song. */ static int sound_al_loadOgg( alSound *snd, OggVorbis_File *vf ) { int ret; long i; int section; vorbis_info *info; ALenum format; ogg_int64_t len; char *buf; /* Finish opening the file. */ ret = ov_test_open(vf); if (ret) { WARN("Failed to finish loading OGG file: %s", vorbis_getErr(ret) ); return -1; } /* Get file information. */ info = ov_info( vf, -1 ); format = (info->channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; len = ov_pcm_total( vf, -1 ) * info->channels * 2; /* Allocate memory. */ buf = malloc( len ); /* Fill buffer. */ i = 0; while (i < len) { /* Fill buffer with data in the 16 bit signed samples format. */ i += ov_read( vf, &buf[i], len-i, VORBIS_ENDIAN, 2, 1, §ion ); } soundLock(); /* Create new buffer. */ alGenBuffers( 1, &snd->u.al.buf ); /* Put into buffer. */ alBufferData( snd->u.al.buf, format, buf, len, info->rate ); soundUnlock(); /* Clean up. */ free(buf); ov_clear(vf); return 0; }
/** * @brief Resumes a group. */ void sound_al_resumeGroup( int group ) { int i; alGroup_t *g; for (i=0; i<al_ngroups; i++) { if (al_groups[i].id == group) { g = &al_groups[i]; soundLock(); al_resumev( g->nsources, g->sources ); soundUnlock(); break; } } if (i>=al_ngroups) WARN("Group '%d' not found.", group); }
/** * @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 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 Internal volume update function. */ static void sound_al_volumeUpdate (void) { int i, j; alGroup_t *g; double v; soundLock(); /* Do generic ones. */ for (i=0; i<source_ntotal; i++) alSourcef( source_total[i], AL_GAIN, svolume*svolume_speed ); /* Do specific groups. */ for (i=0; i<al_ngroups; i++) { g = &al_groups[i]; v = svolume * g->volume; if (g->speed) v *= svolume_speed; for (j=0; j<g->nsources; j++) alSourcef( g->sources[j], AL_GAIN, v ); } soundUnlock(); }
/** * @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 Loads a wav file from the rw if possible. * * @note Closes the rw. * * @param snd Sound to load wav into. * @param rw Data for the wave. */ static int sound_al_loadWav( alSound *snd, SDL_RWops *rw ) { int len; uint32_t i; char magic[4], *buf; ALenum format; uint32_t filelen, chunklen, rate, unused32; uint16_t compressed, channels, align, unused16; /* Some initialization. */ compressed = 0; channels = 0; /* Seek to start. */ SDL_RWseek( rw, 0, SEEK_SET ); /* Check RIFF header. */ if (sound_al_wavReadCmp( rw, "RIFF", 4 )) { WARN("RIFF header not found."); goto wav_err; } /* Get file length. */ if (sound_al_wavGetLen32( rw, &filelen )) { WARN("Unable to get WAVE length."); goto wav_err; } /* Check WAVE header. */ if (sound_al_wavReadCmp( rw, "WAVE", 4 )) { WARN("WAVE header not found."); goto wav_err; } /* * Chunk information header. */ /* Check chunk header. */ if (sound_al_wavReadCmp( rw, "fmt ", 4 )) { WARN("Chunk header 'fmt ' header not found."); goto wav_err; } /* Get chunk length. */ if (sound_al_wavGetLen32( rw, &chunklen )) { WARN("Unable to get WAVE chunk length."); goto wav_err; } i = 0; /* Get compression. */ if (sound_al_wavGetLen16( rw, &compressed )) { WARN("Unable to get WAVE chunk compression type."); goto wav_err; } if (compressed != 0x0001) { WARN("Unsupported WAVE chunk compression '0x%04x'.", compressed); goto wav_err; } i += 2; /* Get channels. */ if (sound_al_wavGetLen16( rw, &channels )) { WARN("Unable to get WAVE chunk channels."); goto wav_err; } i += 2; /* Get sample rate. */ if (sound_al_wavGetLen32( rw, &rate )) { WARN("Unable to get WAVE chunk sample rate."); goto wav_err; } i += 4; /* Get average bytes. */ if (sound_al_wavGetLen32( rw, &unused32 )) { WARN("Unable to get WAVE chunk average byte rate."); goto wav_err; } i += 4; /* Get block align. */ if (sound_al_wavGetLen16( rw, &unused16 )) { WARN("Unable to get WAVE chunk block align."); goto wav_err; } i += 2; /* Get significant bits. */ if (sound_al_wavGetLen16( rw, &align )) { WARN("Unable to get WAVE chunk significant bits."); goto wav_err; } align /= channels; i += 2; /* Seek to end. */ SDL_RWseek( rw, chunklen-i, SEEK_CUR ); /* Read new header. */ len = SDL_RWread( rw, magic, 4, 1 ); if (len != 1) { WARN("Unable to read chunk header."); goto wav_err; } /* Skip fact. */ if (memcmp( magic, "fact", 4)==0) { /* Get chunk length. */ if (sound_al_wavGetLen32( rw, &chunklen )) { WARN("Unable to get WAVE chunk data length."); goto wav_err; } /* Seek to end of chunk. */ SDL_RWseek( rw, chunklen, SEEK_CUR ); /* Read new header. */ len = SDL_RWread( rw, magic, 4, 1 ); if (len != 1) { WARN("Unable to read chunk header."); goto wav_err; } } /* Should be chunk header now. */ if (memcmp( magic, "data", 4)) { WARN("Unable to find WAVE 'data' chunk header."); goto wav_err; } /* * Chunk data header. */ /* Get chunk length. */ if (sound_al_wavGetLen32( rw, &chunklen )) { WARN("Unable to get WAVE chunk data length."); goto wav_err; } /* Load the chunk data. */ buf = malloc( chunklen ); i = 0; while (i < chunklen) { i += SDL_RWread( rw, &buf[i], 1, chunklen-i ); } /* Calculate format. */ if (channels == 2) { if (align == 16) format = AL_FORMAT_STEREO16; else if (align == 8) format = AL_FORMAT_STEREO8; else { WARN("Unsupported byte alignment (%d) in WAVE file.", align); goto chunk_err; } } else if (channels == 1) { if (align == 16) format = AL_FORMAT_MONO16; else if (align == 8) format = AL_FORMAT_MONO8; else { WARN("Unsupported byte alignment (%d) in WAVE file.", align); goto chunk_err; } } else { WARN("Unsupported number of channels (%d) in WAVE file.", channels); goto chunk_err; } soundLock(); /* Create new buffer. */ alGenBuffers( 1, &snd->u.al.buf ); /* Put into the buffer. */ alBufferData( snd->u.al.buf, format, buf, chunklen, rate ); soundUnlock(); free(buf); return 0; chunk_err: free(buf); wav_err: return -1; }
/** * @brief Loads a buffer. * * @param buffer Buffer to load. */ static int stream_loadBuffer( ALuint buffer ) { int ret, size, section, result; musicVorbisLock(); /* Make sure music is valid. */ if (music_vorbis.rw == NULL) { musicVorbisUnlock(); return -1; } ret = 0; size = 0; while (size < music_bufSize) { /* fille up the entire data buffer */ result = ov_read_filter( &music_vorbis.stream, /* stream */ &music_buf[size], /* data */ music_bufSize - size, /* amount to read */ VORBIS_ENDIAN, /* big endian? */ 2, /* 16 bit */ 1, /* signed */ §ion, /* current bitstream */ rg_filter, /* filter function */ &music_vorbis ); /* filter parameter */ /* End of file. */ if (result == 0) { if (size == 0) { musicVorbisUnlock(); return -2; } ret = 1; break; } /* Hole error. */ else if (result == OV_HOLE) { musicVorbisUnlock(); WARN("OGG: Vorbis hole detected in music!"); return 0; } /* Bad link error. */ else if (result == OV_EBADLINK) { musicVorbisUnlock(); WARN("OGG: Invalid stream section or corrupt link in music!"); return -1; } size += result; } musicVorbisUnlock(); /* load the buffer up */ soundLock(); alBufferData( buffer, music_vorbis.format, music_buf, size, music_vorbis.info->rate ); soundUnlock(); return ret; }
/** * @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; }