
com.threerings.openal.SoundGroup Maven / Gradle / Ivy
//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2012 Three Rings Design, Inc., All Rights Reserved
// https://github.com/threerings/nenya
//
// This library 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; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library 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 library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.openal;
import java.util.ArrayList;
import org.lwjgl.openal.AL10;
import com.google.common.collect.Lists;
import static com.threerings.openal.Log.log;
/**
* Manages a group of sounds, binding them to OpenAL sources as they are played and freeing up
* those sources for use by other sounds when the sounds are finished.
*/
public class SoundGroup
{
/**
* Sets the base gain for this group, or -1 to inherit from the manager (the default).
*/
public void setBaseGain (float gain)
{
if (_baseGain != gain) {
_baseGain = gain;
baseGainChanged();
}
}
/**
* Returns the base gain for this group, or -1 if inherited from the manager.
*/
public float getBaseGain ()
{
return _baseGain;
}
/**
* Queues up the specified sound clip for pre-loading into the cache.
*/
public void preloadClip (String path)
{
if (_manager.isInitialized()) {
_manager.getClip(_provider, path);
}
}
/**
* Obtains an "instance" of the specified sound which can be positioned, played, looped and
* otherwise used to make noise.
*/
public Sound getSound (String path)
{
ClipBuffer buffer = null;
if (_manager.isInitialized()) {
buffer = _manager.getClip(_provider, path);
}
return (buffer == null) ? new BlankSound() : new Sound(this, buffer);
}
/**
* Disposes this sound group, freeing up the OpenAL sources with which it is associated. All
* sounds obtained from this group will no longer be usable and should be discarded.
*/
public void dispose ()
{
reclaimAll();
for (PooledSource pooled : _sources) {
pooled.source.delete();
}
_sources.clear();
// remove from the manager
_manager.removeGroup(this);
}
/**
* Stops and reclaims all sounds from this sound group but does not free the sources.
*/
public void reclaimAll ()
{
// make sure any bound sources are released
for (PooledSource pooled : _sources) {
if (pooled.holder != null) {
pooled.holder.stop();
pooled.holder.reclaim();
pooled.holder = null;
}
}
}
protected SoundGroup (SoundManager manager, ClipProvider provider, int sources)
{
_manager = manager;
_provider = provider;
// register with the manager
_manager.addGroup(this);
// if we were unable to initialize the sound system at all, just
// stop here and we'll behave as if we have no available sources
if (!_manager.isInitialized()) {
return;
}
// create our sources (or as many of them as we can)
for (int ii = 0; ii < sources; ii++) {
AL10.alGetError(); // throw away any unchecked error prior to an op we want to check
PooledSource pooled = new PooledSource();
pooled.source = new Source(manager);
int errno = AL10.alGetError();
if (errno != AL10.AL_NO_ERROR) {
log.warning("Failed to create sources [cprov=" + provider +
", sources=" + sources + ", errno=" + errno + "].");
return;
}
_sources.add(pooled);
}
}
/**
* Called by a {@link Sound} when it wants to obtain a source on which to play its clip.
*/
protected Source acquireSource (Sound acquirer)
{
// start at the beginning of the list looking for an available source
for (int ii = 0, ll = _sources.size(); ii < ll; ii++) {
PooledSource pooled = _sources.get(ii);
if (pooled.holder == null || pooled.holder.reclaim()) {
// note this source's new holder
pooled.holder = acquirer;
// move this source to the end of the list
_sources.remove(ii);
_sources.add(pooled);
return pooled.source;
}
}
return null;
}
/**
* Used to pass the base gain through to sound effects.
*/
protected float getInheritedBaseGain ()
{
return (_baseGain < 0f) ? _manager.getBaseGain() : _baseGain;
}
/**
* Called by the manager when the base gain has changed.
*/
protected void baseGainChanged ()
{
// notify any sound currently holding a source
for (int ii = 0, nn = _sources.size(); ii < nn; ii++) {
Sound holder = _sources.get(ii).holder;
if (holder != null) {
holder.updateSourceGain();
}
}
}
/** Used to track which sources are in use. */
protected static class PooledSource
{
public Source source;
public Sound holder;
}
protected SoundManager _manager;
protected ClipProvider _provider;
protected ArrayList _sources = Lists.newArrayList();
/** The base gain, or -1 to inherit from the manager. */
protected float _baseGain = -1f;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy