Fixed some audio issues, refactoring

master
Ondřej Hruška 10 years ago
parent abd5bec682
commit 6d901ddfe5
  1. 99
      src/mightypork/gamecore/audio/AudioModule.java
  2. 24
      src/mightypork/gamecore/audio/DeferredAudio.java
  3. 77
      src/mightypork/gamecore/audio/IAudio.java
  4. 37
      src/mightypork/gamecore/audio/SoundRegistry.java
  5. 81
      src/mightypork/gamecore/audio/players/AudioPlayer.java
  6. 56
      src/mightypork/gamecore/audio/players/EffectPlayer.java
  7. 95
      src/mightypork/gamecore/audio/players/LoopPlayer.java
  8. 4
      src/mightypork/gamecore/graphics/GraphicsModule.java
  9. 2
      src/mightypork/gamecore/graphics/textures/TextureRegistry.java

@ -19,50 +19,50 @@ import mightypork.utils.math.constraints.vect.Vect;
* @author Ondřej Hruška (MightyPork)
*/
public abstract class AudioModule extends BackendModule implements Updateable {
/**
* Set listener position
*
* @param pos listener position
*/
public abstract void setListenerPos(Vect pos);
/**
* Get current listener position
*
* @return listener position
*/
public abstract Vect getListenerPos();
// -- instance --
private final Volume masterVolume = new Volume(1D);
private final Volume effectsVolume = new JointVolume(masterVolume);
private final Volume loopsVolume = new JointVolume(masterVolume);
private final List<LoopPlayer> loopPlayers = new ArrayList<>();
private final List<DeferredAudio> resources = new ArrayList<>();
@Override
public void destroy()
{
for (final DeferredAudio r : resources) {
r.destroy();
}
deinitSoundSystem();
}
/**
* Deinitialize the soud system, release resources etc.<br>
* Audio resources are already destroyed.
*/
protected abstract void deinitSoundSystem();
@Override
public void update(double delta)
{
@ -70,67 +70,64 @@ public abstract class AudioModule extends BackendModule implements Updateable {
lp.update(delta);
}
}
/**
* Create effect resource
*
* @param resource resource path
* @param pitch default pitch (1 = unchanged)
* @param gain default gain (0-1)
* @return player
*/
public EffectPlayer createEffect(String resource, double pitch, double gain)
public EffectPlayer createEffect(String resource)
{
return new EffectPlayer(createAudio(resource), pitch, gain, effectsVolume);
return new EffectPlayer(createAudioResource(resource), effectsVolume);
}
/**
* Register loop resource (music / effect loop)
*
* @param resource resource path
* @param pitch default pitch (1 = unchanged)
* @param gain default gain (0-1)
* @param fadeIn default time for fadeIn
* @param fadeOut default time for fadeOut
* @return player
*/
public LoopPlayer createLoop(String resource, double pitch, double gain, double fadeIn, double fadeOut)
public LoopPlayer createLoop(String resource)
{
final LoopPlayer p = new LoopPlayer(createAudio(resource), pitch, gain, loopsVolume);
p.setFadeTimes(fadeIn, fadeOut);
final LoopPlayer p = new LoopPlayer(createAudioResource(resource), loopsVolume);
loopPlayers.add(p);
return p;
}
/**
* Create {@link DeferredAudio} for a resource, request deferred load and
* add to the resources list.
* add to the resources list.<br>
* The method is accessed only from within this class, since the sound
* registry holds players, not the resources themselves.
*
* @param res a resource name
* @return the resource
* @throws IllegalArgumentException if resource is already registered
*/
protected DeferredAudio createAudio(String res)
protected final DeferredAudio createAudioResource(String res)
{
final DeferredAudio a = doCreateResource(res);
App.bus().send(new ResourceLoadRequest(a));
resources.add(a);
return a;
}
/**
* Create a backend-specific deferred audio resource
* Create a backend-specific deferred audio resource.<br>
* The actual resource instance should be created here. Registering, loading
* etc. is handled higher.
*
* @param res resource path
* @return Deferred Audio
*/
protected abstract DeferredAudio doCreateResource(String res);
/**
* Fade out all loops (= fade out the currently playing loops)
*/
@ -140,8 +137,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
p.fadeOut();
}
}
/**
* Pause all loops (leave volume unchanged)
*/
@ -151,8 +148,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
p.pause();
}
}
/**
* Set level of master volume (volume multiplier)
*
@ -162,8 +159,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
{
masterVolume.set(volume);
}
/**
* Set level of effects volume (volume multiplier)
*
@ -173,8 +170,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
{
effectsVolume.set(volume);
}
/**
* Set level of loops volume (volume multiplier)
*
@ -184,8 +181,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
{
loopsVolume.set(volume);
}
/**
* Get level of master volume (volume multiplier)
*
@ -195,8 +192,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
{
return masterVolume.get();
}
/**
* Get level of effects volume (volume multiplier)
*
@ -206,8 +203,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
{
return effectsVolume.get();
}
/**
* Get level of loops volume (volume multiplier)
*

@ -24,25 +24,25 @@ public abstract class DeferredAudio extends BaseDeferredResource implements IAud
{
super(resourceName);
}
@Override
public void play(double pitch, double gain, boolean loop)
public void play(double gain, double pitch, boolean loop)
{
play(pitch, gain, loop, App.audio().getListenerPos());
play(gain, pitch, loop, App.audio().getListenerPos());
}
@Override
public void play(double pitch, double gain, boolean loop, double x, double y)
public void play(double gain, double pitch, boolean loop, double x, double y)
{
play(pitch, gain, loop, x, y, App.audio().getListenerPos().z());
play(gain, pitch, loop, x, y, App.audio().getListenerPos().z());
}
@Override
public void play(double pitch, double gain, boolean loop, Vect pos)
public void play(double gain, double pitch, boolean loop, Vect pos)
{
play(pitch, gain, loop, pos.x(), pos.y(), pos.z());
play(gain, pitch, loop, pos.x(), pos.y(), pos.z());
}
}

@ -11,19 +11,19 @@ import mightypork.utils.math.constraints.vect.Vect;
* @author Ondřej Hruška (MightyPork)
*/
public interface IAudio extends Destroyable {
/**
* Pause loop (remember position and stop playing) - if was looping
*/
void pauseLoop();
/**
* Resume loop (if was paused)
*/
void resumeLoop();
/**
* Adjust gain for the currently playing effect (can be used for fading
* music)
@ -31,20 +31,20 @@ public interface IAudio extends Destroyable {
* @param gain gain to set 0..1
*/
void adjustGain(double gain);
/**
* Stop audio playback
* Stop audio playback, free source.
*/
void stop();
/**
* @return true if the audio is playing
*/
boolean isPlaying();
/**
* @return trie if the audio is paused
*/
@ -54,46 +54,55 @@ public interface IAudio extends Destroyable {
/**
* Play as sound effect at listener position
*
* @param pitch pitch (1 = default)
* @param gain gain (0-1)
* @param gain gain
* @param pitch pitch
* @param loop looping
*/
void play(double pitch, double gain, boolean loop);
void play(double gain, double pitch, boolean loop);
/**
* Play as sound effect at given X-Y position
* Play as sound effect at given position
*
* @param pitch pitch (1 = default)
* @param gain gain (0-1)
* @param gain gain
* @param pitch pitch
* @param loop looping
* @param x
* @param y
* @param z
*/
void play(double pitch, double gain, boolean loop, double x, double y);
void play(double gain, double pitch, boolean loop, double x, double y, double z);
/**
* Play as sound effect at given position
* Play as sound effect at given X-Y position
*
* @param pitch pitch (1 = default)
* @param gain gain (0-1)
* @param gain gain
* @param pitch pitch
* @param loop looping
* @param x
* @param y
* @param z
*/
void play(double pitch, double gain, boolean loop, double x, double y, double z);
void play(double gain, double pitch, boolean loop, double x, double y);
/**
* Play as sound effect at given position
*
* @param pitch pitch (1 = default)
* @param gain gain (0-1)
* @param gain gain
* @param pitch pitch
* @param loop looping
* @param pos coord
*/
void play(double pitch, double gain, boolean loop, Vect pos);
void play(double gain, double pitch, boolean loop, Vect pos);
/**
* Check if this audio is currently active (ie. playing or paused, not
* stopped)
*
* @return is active
*/
boolean isActive();
}

@ -6,7 +6,6 @@ import java.util.Map;
import mightypork.gamecore.audio.players.EffectPlayer;
import mightypork.gamecore.audio.players.LoopPlayer;
import mightypork.gamecore.core.App;
/**
@ -15,41 +14,35 @@ import mightypork.gamecore.core.App;
* @author Ondřej Hruška (MightyPork)
*/
public class SoundRegistry {
private final Map<String, EffectPlayer> effects = new HashMap<>();
private final Map<String, LoopPlayer> loops = new HashMap<>();
/**
* Register effect resource
*
* @param key sound key
* @param resource resource path
* @param pitch default pitch (1 = unchanged)
* @param gain default gain (0-1)
* @param effect the effect to add (Obtained from audio module)
*/
public void addEffect(String key, String resource, double pitch, double gain)
public void addEffect(String key, EffectPlayer effect)
{
effects.put(key, App.audio().createEffect(resource, pitch, gain));
effects.put(key, effect);
}
/**
* Register loop resource (music / effect loop)
*
* @param key sound key
* @param resource resource path
* @param pitch default pitch (1 = unchanged)
* @param gain default gain (0-1)
* @param fadeIn default time for fadeIn
* @param fadeOut default time for fadeOut
* @param loop the loop to add (Obtained from audio module)
*/
public void addLoop(String key, String resource, double pitch, double gain, double fadeIn, double fadeOut)
public void addLoop(String key, LoopPlayer loop)
{
loops.put(key, App.audio().createLoop(resource, pitch, gain, fadeIn, fadeOut));
loops.put(key, loop);
}
/**
* Get a loop player for key
*
@ -64,8 +57,8 @@ public class SoundRegistry {
}
return p;
}
/**
* Get a effect player for key
*

@ -1,66 +1,61 @@
package mightypork.gamecore.audio.players;
import mightypork.gamecore.audio.DeferredAudio;
import mightypork.gamecore.audio.IAudio;
import mightypork.gamecore.audio.Volume;
import mightypork.utils.interfaces.Destroyable;
/**
* Basic abstract player
* Base of an audio player
*
* @author Ondřej Hruška (MightyPork)
*/
public abstract class BaseAudioPlayer implements Destroyable {
public abstract class AudioPlayer implements Destroyable {
/** the track */
private final DeferredAudio audio;
private final IAudio audio;
/** base gain for sfx */
private final double baseGain;
private double baseGain;
/** base pitch for sfx */
private final double basePitch;
private double basePitch;
/** dedicated volume control */
private final Volume gainMultiplier;
/**
* @param track audio resource
* @param basePitch base pitch (pitch multiplier)
* @param baseGain base gain (volume multiplier)
* @param volume colume control
*/
public BaseAudioPlayer(DeferredAudio track, double basePitch, double baseGain, Volume volume)
public AudioPlayer(IAudio track, Volume volume)
{
this.audio = track;
this.baseGain = baseGain;
this.basePitch = basePitch;
if (volume == null) volume = new Volume(1D);
this.gainMultiplier = volume;
}
@Override
public void destroy()
{
audio.destroy();
}
/**
* @return audio resource
*/
protected DeferredAudio getAudio()
protected IAudio getAudio()
{
return audio;
}
/**
* Get play gain, computed based on volume and given multiplier
*
@ -71,8 +66,8 @@ public abstract class BaseAudioPlayer implements Destroyable {
{
return baseGain * gainMultiplier.get() * multiplier;
}
/**
* Get pitch
*
@ -83,8 +78,8 @@ public abstract class BaseAudioPlayer implements Destroyable {
{
return basePitch * multiplier;
}
/**
* Get if audio is valid
*
@ -94,13 +89,27 @@ public abstract class BaseAudioPlayer implements Destroyable {
{
return (audio != null);
}
/**
* Set base gain. 1 is original volume, 0 is silence.
*
* @param baseGain base gain
*/
public void setGain(double baseGain)
{
this.baseGain = baseGain;
}
/**
* force load the resource
* Set base pitch. 1 is original pitch, less is deeper, more is higher.
*
* @param basePitch base pitch
*/
public void load()
public void setPitch(double basePitch)
{
if (hasAudio()) audio.load();
this.basePitch = basePitch;
}
}

@ -1,7 +1,7 @@
package mightypork.gamecore.audio.players;
import mightypork.gamecore.audio.DeferredAudio;
import mightypork.gamecore.audio.IAudio;
import mightypork.gamecore.audio.Volume;
import mightypork.utils.math.constraints.vect.Vect;
@ -11,34 +11,32 @@ import mightypork.utils.math.constraints.vect.Vect;
*
* @author Ondřej Hruška (MightyPork)
*/
public class EffectPlayer extends BaseAudioPlayer {
public class EffectPlayer extends AudioPlayer {
/**
* @param track audio resource
* @param basePitch base pitch (pitch multiplier)
* @param baseGain base gain (volume multiplier)
* @param volume volume control
*/
public EffectPlayer(DeferredAudio track, double basePitch, double baseGain, Volume volume)
public EffectPlayer(IAudio track, Volume volume)
{
super(track, (float) basePitch, (float) baseGain, volume);
super(track, volume);
}
/**
* Play at listener
*
* @param pitch play pitch
* @param gain play gain
* @param pitch play pitch
*/
public void play(double pitch, double gain)
public void play(double gain, double pitch)
{
if (!hasAudio()) return;
getAudio().play(computePitch(pitch), computeGain(gain), false);
getAudio().play(computeGain(gain), computePitch(pitch), false);
}
/**
* Play at listener
*
@ -46,22 +44,34 @@ public class EffectPlayer extends BaseAudioPlayer {
*/
public void play(double gain)
{
play(1, gain);
play(gain, 1);
}
/**
* Play at given position
*
* @param pitch play pitch
* @param gain play gain
* @param pos play position
*/
public void play(double pitch, double gain, Vect pos)
public void play(double gain, Vect pos)
{
play(gain, 1, pos);
}
/**
* Play at given position
*
* @param gain play gain
* @param pitch play pitch
* @param pos play position
*/
public void play(double gain, double pitch, Vect pos)
{
if (!hasAudio()) return;
getAudio().play(computePitch(pitch), computeGain(gain), false, pos);
getAudio().play(computeGain(gain), computePitch(pitch), false, pos);
}
}

@ -13,33 +13,31 @@ import mightypork.utils.math.animation.NumAnimated;
*
* @author Ondřej Hruška (MightyPork)
*/
public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable {
public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable {
/** animator for fade in and fade out */
private final NumAnimated fadeAnim = new NumAnimated(0);
private double lastUpdateGain = 0;
/** flag that track is paused */
private boolean paused = true;
/** Default fadeIn time */
private double inTime = 1;
/** Default fadeOut time */
private double outTime = 1;
/**
* @param track audio resource
* @param basePitch base pitch (pitch multiplier)
* @param baseGain base gain (volume multiplier)
* @param volume volume control
*/
public LoopPlayer(DeferredAudio track, double basePitch, double baseGain, Volume volume)
public LoopPlayer(DeferredAudio track, Volume volume)
{
super(track, (float) basePitch, (float) baseGain, volume);
super(track, volume);
paused = true;
}
@ -55,68 +53,77 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
inTime = in;
outTime = out;
}
private void initLoop()
{
if (hasAudio()) {
getAudio().play(computePitch(1), computeGain(1), true);
if (hasAudio() && !getAudio().isActive()) {
getAudio().play(computeGain(1), computePitch(1), true);
getAudio().pauseLoop();
}
}
@Override
public void pause()
{
if (!hasAudio() || paused) return;
initLoop();
getAudio().pauseLoop();
paused = true;
}
@Override
public boolean isPaused()
{
return paused;
}
/**
* Alias to resume (more meaningful name)
*/
public void play()
{
resume();
}
@Override
public void resume()
{
if (!hasAudio() || !paused) return;
initLoop();
paused = false;
getAudio().adjustGain(computeGain(fadeAnim.value()));
}
@Override
public void update(double delta)
{
if (!hasAudio() || paused) return;
initLoop();
fadeAnim.update(delta);
final double gain = computeGain(fadeAnim.value());
if (!paused && gain != lastUpdateGain) {
getAudio().adjustGain(gain);
lastUpdateGain = gain;
}
if (gain == 0 && !paused) pause(); // pause on zero volume
}
/**
* Resume if paused, and fade in (pick up from current volume).
*
@ -125,13 +132,13 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
public void fadeIn(double fadeTime)
{
if (!hasAudio()) return;
if (isPaused()) fadeAnim.setTo(0);
resume();
fadeAnim.fadeIn(fadeTime);
}
/**
* Fade out and pause when reached zero volume
*
@ -143,8 +150,8 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
if (isPaused()) return;
fadeAnim.fadeOut(fadeTime);
}
/**
* Fade in with default duration
*/
@ -152,8 +159,8 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
{
fadeIn(inTime);
}
/**
* Fade out with default duration
*/
@ -161,5 +168,5 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
{
fadeOut(outTime);
}
}

@ -272,7 +272,7 @@ public abstract class GraphicsModule extends BackendModule {
* @param path path to texture
* @return the deferred font
*/
public abstract DeferredTexture createDeferredTexture(String path);
public abstract DeferredTexture createTextureResource(String path);
/**
@ -281,7 +281,7 @@ public abstract class GraphicsModule extends BackendModule {
* @param path path to font, or font name in the system
* @return the deferred font
*/
public abstract DeferredFont createDeferredFont(String path);
public abstract DeferredFont createFontResource(String path);
/**

@ -51,7 +51,7 @@ public class TextureRegistry {
{
if (key != null) if (textures.containsKey(key)) throw new KeyAlreadyExistsException();
final DeferredTexture texture = App.gfx().createDeferredTexture(resourcePath);
final DeferredTexture texture = App.gfx().createTextureResource(resourcePath);
texture.setFilter(filter);
texture.setWrap(wrap);

Loading…
Cancel
Save