Audio improvements
This commit is contained in:
@@ -15,20 +15,23 @@ import mightypork.gamecore.eventbus.event_flags.SingleReceiverEvent;
|
||||
public class MainLoopRequest extends BusEvent<MainLoop> {
|
||||
|
||||
private final Runnable task;
|
||||
private final boolean priority;
|
||||
|
||||
|
||||
/**
|
||||
* @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.priority = priority;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
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.event_flags.NonConsumableEvent;
|
||||
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();
|
||||
}
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
package mightypork.gamecore.core.modules;
|
||||
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import mightypork.gamecore.eventbus.events.UpdateEvent;
|
||||
import mightypork.gamecore.gui.screens.ScreenRegistry;
|
||||
import mightypork.gamecore.logging.Log;
|
||||
import mightypork.gamecore.render.Renderable;
|
||||
import mightypork.gamecore.render.TaskTakeScreenshot;
|
||||
import mightypork.gamecore.render.events.ScreenshotRequestListener;
|
||||
import mightypork.gamecore.resources.Profiler;
|
||||
import mightypork.gamecore.util.Utils;
|
||||
import mightypork.gamecore.util.annot.DefaultImpl;
|
||||
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 {
|
||||
|
||||
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 Renderable rootRenderable;
|
||||
private volatile boolean running = true;
|
||||
@@ -58,11 +65,23 @@ public class MainLoop extends AppModule implements ScreenshotRequestListener {
|
||||
while (running) {
|
||||
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;
|
||||
while ((r = taskQueue.poll()) != null) {
|
||||
long t = Profiler.begin();
|
||||
while ((r = tasks.poll()) != null) {
|
||||
Log.f3(" * Main loop task.");
|
||||
r.run();
|
||||
if (Profiler.end(t) > MAX_TIME_TASKS) {
|
||||
Log.f3("! Postponing main loop tasks to next cycle.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
*
|
||||
* @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());
|
||||
}
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -67,6 +67,11 @@ public class CrossfadeOverlay extends Overlay {
|
||||
{
|
||||
requestedScreenName = screen;
|
||||
|
||||
if(screen == null) {
|
||||
// going for halt
|
||||
getSoundSystem().fadeOutAllLoops();
|
||||
}
|
||||
|
||||
if (fromDark) {
|
||||
alpha.setTo(1);
|
||||
revealTask.run();
|
||||
|
||||
@@ -3,6 +3,7 @@ package mightypork.gamecore.gui.screens.impl;
|
||||
|
||||
import mightypork.gamecore.gui.screens.Screen;
|
||||
import mightypork.gamecore.gui.screens.ScreenLayer;
|
||||
import mightypork.gamecore.util.annot.DefaultImpl;
|
||||
import mightypork.gamecore.util.math.Easing;
|
||||
import mightypork.gamecore.util.math.constraints.num.mutable.NumAnimated;
|
||||
import mightypork.gamecore.util.math.timing.TimedTask;
|
||||
@@ -73,6 +74,7 @@ public abstract class FadingLayer extends ScreenLayer {
|
||||
/**
|
||||
* Called after the fade-out was completed
|
||||
*/
|
||||
@DefaultImpl
|
||||
protected void onHideFinished()
|
||||
{
|
||||
}
|
||||
@@ -81,6 +83,7 @@ public abstract class FadingLayer extends ScreenLayer {
|
||||
/**
|
||||
* Called after the fade-in was completed
|
||||
*/
|
||||
@DefaultImpl
|
||||
protected void onShowFinished()
|
||||
{
|
||||
}
|
||||
@@ -98,6 +101,7 @@ public abstract class FadingLayer extends ScreenLayer {
|
||||
super.show();
|
||||
numa.fadeIn();
|
||||
hideTimer.stop();
|
||||
showTimer.start(numa.getDefaultDuration());
|
||||
|
||||
fadingOut = false;
|
||||
fadingIn = true;
|
||||
|
||||
@@ -18,7 +18,7 @@ import mightypork.gamecore.logging.Log;
|
||||
*/
|
||||
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 volatile boolean stopped;
|
||||
@@ -57,9 +57,9 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr
|
||||
if (resource.getClass().isAnnotationPresent(TextureBasedResource.class)) {
|
||||
|
||||
if (!mainLoopQueuing) {
|
||||
Log.f3("<LOADER> Cannot load async: " + Log.str(resource));
|
||||
// just let it be
|
||||
} 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() {
|
||||
|
||||
@@ -68,7 +68,7 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr
|
||||
{
|
||||
resource.load();
|
||||
}
|
||||
}));
|
||||
}, false));
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -91,14 +91,16 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr
|
||||
|
||||
if (!def.isLoaded()) {
|
||||
|
||||
Log.f3("<LOADER> Loading: " + Log.str(def));
|
||||
Log.f3("(loader) Scheduling... " + Log.str(def));
|
||||
|
||||
exs.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
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.logging.Log;
|
||||
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.");
|
||||
}
|
||||
|
||||
Log.f3("<RES> Loading: " + this);
|
||||
long time = Profiler.begin();
|
||||
Log.f3("(res) + Load: " + this);
|
||||
loadResource(resource);
|
||||
Log.f3("<RES> Loaded: " + this);
|
||||
Log.f3("(res) - Done: " + this + " in " + Profiler.endStr(time));
|
||||
|
||||
} catch (final Throwable t) {
|
||||
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 {
|
||||
if (loadFailed) return false;
|
||||
|
||||
Log.f3("<RES> (!) Loading on access: " + this);
|
||||
Log.f3("(res) !! Loading on access: " + this);
|
||||
load();
|
||||
}
|
||||
|
||||
@@ -99,7 +103,7 @@ public abstract class BaseLazyResource implements LazyResource, Destroyable {
|
||||
@Override
|
||||
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)
|
||||
{
|
||||
binder.addFonts(fonts);
|
||||
binder.addSounds(sounds);
|
||||
binder.addTextures(textures);
|
||||
binder.addSounds(sounds);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package mightypork.gamecore.resources.audio;
|
||||
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
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 loopsVolume = new JointVolume(masterVolume);
|
||||
|
||||
private final Set<LoopPlayer> loopPlayers = new HashSet<>();
|
||||
private final Set<LazyAudio> resources = new HashSet<>();
|
||||
private final List<LoopPlayer> loopPlayers = new ArrayList<>();
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
final LoopPlayer p = new LoopPlayer(getResource(resource), pitch, gain, loopsVolume);
|
||||
final LoopPlayer p = new LoopPlayer(createResource(resource), pitch, gain, loopsVolume);
|
||||
p.setFadeTimes(fadeIn, fadeOut);
|
||||
loopPlayers.add(p);
|
||||
return p;
|
||||
@@ -160,12 +162,10 @@ public class SoundSystem extends RootBusNode implements Updateable {
|
||||
* @return the resource
|
||||
* @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));
|
||||
|
||||
if (resources.contains(a)) throw new IllegalArgumentException("Sound resource " + res + " is already registered.");
|
||||
resources.add(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,8 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
|
||||
|
||||
sourceID = getAudio().resumeLoop();
|
||||
paused = false;
|
||||
|
||||
adjustGain(getGain(fadeAnim.value()));
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +114,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
|
||||
|
||||
final double gain = getGain(fadeAnim.value());
|
||||
if (!paused && gain != lastUpdateGain) {
|
||||
AL10.alSourcef(sourceID, AL10.AL_GAIN, (float) gain);
|
||||
adjustGain(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).
|
||||
*
|
||||
@@ -129,6 +137,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
|
||||
{
|
||||
if (!hasAudio()) return;
|
||||
|
||||
if (isPaused()) fadeAnim.setTo(0);
|
||||
resume();
|
||||
fadeAnim.fadeIn(secs);
|
||||
}
|
||||
@@ -142,7 +151,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
|
||||
public void fadeOut(double secs)
|
||||
{
|
||||
if (!hasAudio()) return;
|
||||
|
||||
if (isPaused()) return;
|
||||
fadeAnim.fadeOut(secs);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user