Audio improvements

v5stable
Ondřej Hruška 11 years ago
parent a4c485a7de
commit 6220aa9918
  1. 4
      .gitignore
  2. 7
      src/mightypork/gamecore/core/events/MainLoopRequest.java
  3. 3
      src/mightypork/gamecore/core/events/ShudownRequest.java
  4. 36
      src/mightypork/gamecore/core/modules/MainLoop.java
  5. 5
      src/mightypork/gamecore/gui/screens/impl/CrossfadeOverlay.java
  6. 4
      src/mightypork/gamecore/gui/screens/impl/FadingLayer.java
  7. 14
      src/mightypork/gamecore/resources/AsyncResourceLoader.java
  8. 14
      src/mightypork/gamecore/resources/BaseLazyResource.java
  9. 32
      src/mightypork/gamecore/resources/Profiler.java
  10. 2
      src/mightypork/gamecore/resources/Res.java
  11. 16
      src/mightypork/gamecore/resources/audio/SoundSystem.java
  12. 13
      src/mightypork/gamecore/resources/audio/players/LoopPlayer.java

4
.gitignore vendored

@ -1,8 +1,8 @@
/bin/ /bin/
/target/ /target/
/~local/
/.rogue-save/ /.rogue-save/
/build/.rogue-save/ /build/
/build/out/.rogue-save/
/build/out/*.jar /build/out/*.jar
/build/in/*.jar /build/in/*.jar
*.log *.log

@ -15,20 +15,23 @@ import mightypork.gamecore.eventbus.event_flags.SingleReceiverEvent;
public class MainLoopRequest extends BusEvent<MainLoop> { public class MainLoopRequest extends BusEvent<MainLoop> {
private final Runnable task; private final Runnable task;
private final boolean priority;
/** /**
* @param task task to run on main thread in rendering context * @param task task to run on main thread in rendering context
* @param priority if true, skip other tasks in queue
*/ */
public MainLoopRequest(Runnable task) public MainLoopRequest(Runnable task, boolean priority)
{ {
this.task = task; this.task = task;
this.priority = priority;
} }
@Override @Override
public void handleBy(MainLoop handler) public void handleBy(MainLoop handler)
{ {
handler.queueTask(task); handler.queueTask(task, priority);
} }
} }

@ -5,6 +5,7 @@ import mightypork.gamecore.core.modules.MainLoop;
import mightypork.gamecore.eventbus.BusEvent; import mightypork.gamecore.eventbus.BusEvent;
import mightypork.gamecore.eventbus.event_flags.NonConsumableEvent; import mightypork.gamecore.eventbus.event_flags.NonConsumableEvent;
import mightypork.gamecore.eventbus.event_flags.SingleReceiverEvent; import mightypork.gamecore.eventbus.event_flags.SingleReceiverEvent;
import mightypork.gamecore.resources.audio.SoundSystem;
/** /**
@ -27,6 +28,6 @@ public class ShudownRequest extends BusEvent<MainLoop> {
{ {
handler.shutdown(); handler.shutdown();
} }
}); }, true);
} }
} }

@ -1,14 +1,18 @@
package mightypork.gamecore.core.modules; package mightypork.gamecore.core.modules;
import java.util.Deque;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import mightypork.gamecore.eventbus.events.UpdateEvent; import mightypork.gamecore.eventbus.events.UpdateEvent;
import mightypork.gamecore.gui.screens.ScreenRegistry; import mightypork.gamecore.gui.screens.ScreenRegistry;
import mightypork.gamecore.logging.Log;
import mightypork.gamecore.render.Renderable; import mightypork.gamecore.render.Renderable;
import mightypork.gamecore.render.TaskTakeScreenshot; import mightypork.gamecore.render.TaskTakeScreenshot;
import mightypork.gamecore.render.events.ScreenshotRequestListener; import mightypork.gamecore.render.events.ScreenshotRequestListener;
import mightypork.gamecore.resources.Profiler;
import mightypork.gamecore.util.Utils; import mightypork.gamecore.util.Utils;
import mightypork.gamecore.util.annot.DefaultImpl; import mightypork.gamecore.util.annot.DefaultImpl;
import mightypork.gamecore.util.math.timing.TimerDelta; import mightypork.gamecore.util.math.timing.TimerDelta;
@ -21,7 +25,10 @@ import mightypork.gamecore.util.math.timing.TimerDelta;
*/ */
public class MainLoop extends AppModule implements ScreenshotRequestListener { public class MainLoop extends AppModule implements ScreenshotRequestListener {
private final Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<>(); private static final double MAX_TIME_TASKS = 1 / 30D; // (avoid queue from hogging timing)
private static final double MAX_DELTA = 1 / 20D; // (skip huge gaps caused by loading resources etc)
private final Deque<Runnable> tasks = new ConcurrentLinkedDeque<>();
private TimerDelta timer; private TimerDelta timer;
private Renderable rootRenderable; private Renderable rootRenderable;
private volatile boolean running = true; private volatile boolean running = true;
@ -58,11 +65,23 @@ public class MainLoop extends AppModule implements ScreenshotRequestListener {
while (running) { while (running) {
getDisplay().beginFrame(); getDisplay().beginFrame();
getEventBus().sendDirect(new UpdateEvent(timer.getDelta())); double delta = timer.getDelta();
if (delta > MAX_DELTA) {
Log.f3("(timing) Cropping delta: was " + delta + " , limit " + MAX_DELTA);
delta = MAX_DELTA;
}
getEventBus().sendDirect(new UpdateEvent(delta));
Runnable r; Runnable r;
while ((r = taskQueue.poll()) != null) { long t = Profiler.begin();
while ((r = tasks.poll()) != null) {
Log.f3(" * Main loop task.");
r.run(); r.run();
if (Profiler.end(t) > MAX_TIME_TASKS) {
Log.f3("! Postponing main loop tasks to next cycle.");
break;
}
} }
beforeRender(); beforeRender();
@ -109,10 +128,15 @@ public class MainLoop extends AppModule implements ScreenshotRequestListener {
* Add a task to queue to be executed in the main loop (OpenGL thread) * Add a task to queue to be executed in the main loop (OpenGL thread)
* *
* @param request task * @param request task
* @param priority if true, skip other tasks
*/ */
public synchronized void queueTask(Runnable request) public synchronized void queueTask(Runnable request, boolean priority)
{ {
taskQueue.add(request); if (priority) {
tasks.addFirst(request);
} else {
tasks.addLast(request);
}
} }
@ -127,7 +151,7 @@ public class MainLoop extends AppModule implements ScreenshotRequestListener {
{ {
Utils.runAsThread(new TaskTakeScreenshot()); Utils.runAsThread(new TaskTakeScreenshot());
} }
}); }, false);
} }
} }

@ -67,6 +67,11 @@ public class CrossfadeOverlay extends Overlay {
{ {
requestedScreenName = screen; requestedScreenName = screen;
if(screen == null) {
// going for halt
getSoundSystem().fadeOutAllLoops();
}
if (fromDark) { if (fromDark) {
alpha.setTo(1); alpha.setTo(1);
revealTask.run(); revealTask.run();

@ -3,6 +3,7 @@ package mightypork.gamecore.gui.screens.impl;
import mightypork.gamecore.gui.screens.Screen; import mightypork.gamecore.gui.screens.Screen;
import mightypork.gamecore.gui.screens.ScreenLayer; import mightypork.gamecore.gui.screens.ScreenLayer;
import mightypork.gamecore.util.annot.DefaultImpl;
import mightypork.gamecore.util.math.Easing; import mightypork.gamecore.util.math.Easing;
import mightypork.gamecore.util.math.constraints.num.mutable.NumAnimated; import mightypork.gamecore.util.math.constraints.num.mutable.NumAnimated;
import mightypork.gamecore.util.math.timing.TimedTask; import mightypork.gamecore.util.math.timing.TimedTask;
@ -73,6 +74,7 @@ public abstract class FadingLayer extends ScreenLayer {
/** /**
* Called after the fade-out was completed * Called after the fade-out was completed
*/ */
@DefaultImpl
protected void onHideFinished() protected void onHideFinished()
{ {
} }
@ -81,6 +83,7 @@ public abstract class FadingLayer extends ScreenLayer {
/** /**
* Called after the fade-in was completed * Called after the fade-in was completed
*/ */
@DefaultImpl
protected void onShowFinished() protected void onShowFinished()
{ {
} }
@ -98,6 +101,7 @@ public abstract class FadingLayer extends ScreenLayer {
super.show(); super.show();
numa.fadeIn(); numa.fadeIn();
hideTimer.stop(); hideTimer.stop();
showTimer.start(numa.getDefaultDuration());
fadingOut = false; fadingOut = false;
fadingIn = true; fadingIn = true;

@ -18,7 +18,7 @@ import mightypork.gamecore.logging.Log;
*/ */
public class AsyncResourceLoader extends Thread implements ResourceLoader, Destroyable { public class AsyncResourceLoader extends Thread implements ResourceLoader, Destroyable {
private final ExecutorService exs = Executors.newCachedThreadPool(); private final ExecutorService exs = Executors.newFixedThreadPool(2);
private final LinkedBlockingQueue<LazyResource> toLoad = new LinkedBlockingQueue<>(); private final LinkedBlockingQueue<LazyResource> toLoad = new LinkedBlockingQueue<>();
private volatile boolean stopped; private volatile boolean stopped;
@ -57,9 +57,9 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr
if (resource.getClass().isAnnotationPresent(TextureBasedResource.class)) { if (resource.getClass().isAnnotationPresent(TextureBasedResource.class)) {
if (!mainLoopQueuing) { if (!mainLoopQueuing) {
Log.f3("<LOADER> Cannot load async: " + Log.str(resource)); // just let it be
} else { } else {
Log.f3("<LOADER> Delegating to main thread:\n " + Log.str(resource)); Log.f3("(loader) Delegating to main thread: " + Log.str(resource));
app.getEventBus().send(new MainLoopRequest(new Runnable() { app.getEventBus().send(new MainLoopRequest(new Runnable() {
@ -68,7 +68,7 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr
{ {
resource.load(); resource.load();
} }
})); }, false));
} }
return; return;
@ -91,14 +91,16 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr
if (!def.isLoaded()) { if (!def.isLoaded()) {
Log.f3("<LOADER> Loading: " + Log.str(def)); Log.f3("(loader) Scheduling... " + Log.str(def));
exs.submit(new Runnable() { exs.submit(new Runnable() {
@Override @Override
public void run() public void run()
{ {
def.load(); if(!def.isLoaded()) {
def.load();
}
} }
}); });
} }

@ -6,6 +6,8 @@ import java.io.IOException;
import mightypork.gamecore.eventbus.events.Destroyable; import mightypork.gamecore.eventbus.events.Destroyable;
import mightypork.gamecore.logging.Log; import mightypork.gamecore.logging.Log;
import mightypork.gamecore.logging.LogAlias; import mightypork.gamecore.logging.LogAlias;
import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.strings.StringUtils;
/** /**
@ -45,12 +47,14 @@ public abstract class BaseLazyResource implements LazyResource, Destroyable {
throw new NullPointerException("Resource string cannot be null for non-null resource."); throw new NullPointerException("Resource string cannot be null for non-null resource.");
} }
Log.f3("<RES> Loading: " + this); long time = Profiler.begin();
Log.f3("(res) + Load: " + this);
loadResource(resource); loadResource(resource);
Log.f3("<RES> Loaded: " + this); Log.f3("(res) - Done: " + this + " in " + Profiler.endStr(time));
} catch (final Throwable t) { } catch (final Throwable t) {
loadFailed = true; loadFailed = true;
Log.e("<RES> Failed to load: " + this, t); Log.e("(res) Failed to load: " + this, t);
} }
} }
@ -74,7 +78,7 @@ public abstract class BaseLazyResource implements LazyResource, Destroyable {
} else { } else {
if (loadFailed) return false; if (loadFailed) return false;
Log.f3("<RES> (!) Loading on access: " + this); Log.f3("(res) !! Loading on access: " + this);
load(); load();
} }
@ -99,7 +103,7 @@ public abstract class BaseLazyResource implements LazyResource, Destroyable {
@Override @Override
public String toString() public String toString()
{ {
return Log.str(getClass()) + "(\"" + resource + "\")"; return StringUtils.fromLastChar(resource, '/');
} }

@ -0,0 +1,32 @@
package mightypork.gamecore.resources;
import mightypork.gamecore.util.math.Calc;
public class Profiler {
public static long begin()
{
return System.currentTimeMillis();
}
public static double end(long begun)
{
return endLong(begun) / 1000D;
}
public static long endLong(long begun)
{
return System.currentTimeMillis() - begun;
}
public static String endStr(long begun)
{
return Calc.toString(end(begun)) + " s";
}
}

@ -94,8 +94,8 @@ public final class Res {
public static void load(ResourceSetup binder) public static void load(ResourceSetup binder)
{ {
binder.addFonts(fonts); binder.addFonts(fonts);
binder.addSounds(sounds);
binder.addTextures(textures); binder.addTextures(textures);
binder.addSounds(sounds);
} }
} }

@ -2,7 +2,9 @@ package mightypork.gamecore.resources.audio;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import mightypork.gamecore.core.modules.AppAccess; import mightypork.gamecore.core.modules.AppAccess;
@ -71,8 +73,8 @@ public class SoundSystem extends RootBusNode implements Updateable {
private final Volume effectsVolume = new JointVolume(masterVolume); private final Volume effectsVolume = new JointVolume(masterVolume);
private final Volume loopsVolume = new JointVolume(masterVolume); private final Volume loopsVolume = new JointVolume(masterVolume);
private final Set<LoopPlayer> loopPlayers = new HashSet<>(); private final List<LoopPlayer> loopPlayers = new ArrayList<>();
private final Set<LazyAudio> resources = new HashSet<>(); private final List<LazyAudio> resources = new ArrayList<>();
/** /**
@ -130,7 +132,7 @@ public class SoundSystem extends RootBusNode implements Updateable {
*/ */
public EffectPlayer createEffect(String resource, double pitch, double gain) public EffectPlayer createEffect(String resource, double pitch, double gain)
{ {
return new EffectPlayer(getResource(resource), pitch, gain, effectsVolume); return new EffectPlayer(createResource(resource), pitch, gain, effectsVolume);
} }
@ -146,7 +148,7 @@ public class SoundSystem extends RootBusNode implements Updateable {
*/ */
public LoopPlayer createLoop(String resource, double pitch, double gain, double fadeIn, double fadeOut) public LoopPlayer createLoop(String resource, double pitch, double gain, double fadeIn, double fadeOut)
{ {
final LoopPlayer p = new LoopPlayer(getResource(resource), pitch, gain, loopsVolume); final LoopPlayer p = new LoopPlayer(createResource(resource), pitch, gain, loopsVolume);
p.setFadeTimes(fadeIn, fadeOut); p.setFadeTimes(fadeIn, fadeOut);
loopPlayers.add(p); loopPlayers.add(p);
return p; return p;
@ -160,12 +162,10 @@ public class SoundSystem extends RootBusNode implements Updateable {
* @return the resource * @return the resource
* @throws IllegalArgumentException if resource is already registered * @throws IllegalArgumentException if resource is already registered
*/ */
private LazyAudio getResource(String res) private LazyAudio createResource(String res)
{ {
final LazyAudio a = new LazyAudio(res); final LazyAudio a = new LazyAudio(res);
getEventBus().send(new ResourceLoadRequest(a)); getEventBus().send(new ResourceLoadRequest(a));
if (resources.contains(a)) throw new IllegalArgumentException("Sound resource " + res + " is already registered.");
resources.add(a); resources.add(a);
return a; return a;
} }

@ -98,6 +98,8 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
sourceID = getAudio().resumeLoop(); sourceID = getAudio().resumeLoop();
paused = false; paused = false;
adjustGain(getGain(fadeAnim.value()));
} }
@ -112,7 +114,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
final double gain = getGain(fadeAnim.value()); final double gain = getGain(fadeAnim.value());
if (!paused && gain != lastUpdateGain) { if (!paused && gain != lastUpdateGain) {
AL10.alSourcef(sourceID, AL10.AL_GAIN, (float) gain); adjustGain(gain);
lastUpdateGain = gain; lastUpdateGain = gain;
} }
@ -120,6 +122,12 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
} }
private void adjustGain(double gain)
{
AL10.alSourcef(sourceID, AL10.AL_GAIN, (float) gain);
}
/** /**
* Resume if paused, and fade in (pick up from current volume). * Resume if paused, and fade in (pick up from current volume).
* *
@ -129,6 +137,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
{ {
if (!hasAudio()) return; if (!hasAudio()) return;
if (isPaused()) fadeAnim.setTo(0);
resume(); resume();
fadeAnim.fadeIn(secs); fadeAnim.fadeIn(secs);
} }
@ -142,7 +151,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
public void fadeOut(double secs) public void fadeOut(double secs)
{ {
if (!hasAudio()) return; if (!hasAudio()) return;
if (isPaused()) return;
fadeAnim.fadeOut(secs); fadeAnim.fadeOut(secs);
} }

Loading…
Cancel
Save