Skip to content

Commit

Permalink
(#23) Add ability to hook into audio events
Browse files Browse the repository at this point in the history
New Additions:
- `Maths#withinRange` & `Maths.withinIntegerRange`, for constraining a float/int to be between two numbers.
Other Changes:
- Fixed package link in `module-info.java`
  • Loading branch information
lucasstarsz committed May 31, 2021
1 parent 79ddec3 commit 87d138f
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 35 deletions.
2 changes: 1 addition & 1 deletion src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* <p>
* This game library is split into two main parts:
* <ul>
* <li>the framework with which to build games (every package except {@link io.github.lucasstarsz.fastj.engine}), and</li>
* <li>the framework with which to build games (every package except {@link tech.fastj.engine}), and</li>
* <li>the engine running it (just package {@code engine}).</li>
* </ul>
* <p>
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/tech/fastj/math/Maths.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,28 @@ public static boolean floatEquals(float a, float b) {
public static float lerp(float x, float y, float t) {
return (1f - t) * x + t * y;
}

/**
* Ensures the specified number is within the range of the minimum and maximum numbers.
*
* @param num The original number.
* @param min The minimum number allowed.
* @param max The maximum number allowed.
* @return The number, within the range of the minimum and maximum numbers.
*/
public static float withinRange(float num, float min, float max) {
return Math.min(Math.max(num, min), max);
}

/**
* Ensures the specified number is within the range of the minimum and maximum numbers.
*
* @param num The original number.
* @param min The minimum number allowed.
* @param max The maximum number allowed.
* @return The number, within the range of the minimum and maximum numbers.
*/
public static int withinIntegerRange(int num, int min, int max) {
return Math.min(Math.max(num, min), max);
}
}
48 changes: 24 additions & 24 deletions src/main/java/tech/fastj/systems/audio/Audio.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,41 @@

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.FloatControl;
import java.net.URL;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Objects;

public class Audio {

/** Signifies that the audio should loop when it finishes playing. */
public static final int LoopWhenFinishedPlaying = -1;

private Clip clip;
private AudioInputStream audioInputStream;
private final Clip clip;
private final AudioInputStream audioInputStream;
private final SimpleLineListener simpleLineListener;

private Runnable clipOpenAction;
private Runnable clipCloseAction;
private Runnable clipStartAction;
private Runnable clipStopAction;

Audio(URL audioPath) {
clip = AudioManager.newClip();
Audio(Path audioPath) {
clip = Objects.requireNonNull(AudioManager.newClip());
audioInputStream = AudioManager.newAudioStream(audioPath);

clip.addLineListener(new SimpleAudioListener() {
@Override
public void update(LineEvent event) {
LineEvent.Type lineEventType = event.getType();
if (LineEvent.Type.OPEN.equals(lineEventType)) {
clipOpenAction.run();
} else if (LineEvent.Type.CLOSE.equals(lineEventType)) {
clipCloseAction.run();
} else if (LineEvent.Type.START.equals(lineEventType)) {
clipStartAction.run();
} else if (LineEvent.Type.STOP.equals(lineEventType)) {
clipStopAction.run();
simpleLineListener = new SimpleLineListener(
() -> {
},
() -> {
},
() -> {
},
() -> {
clip.stop();
clip.flush();
clip.drain();
clip.close();
}
}
});
);

clip.addLineListener(simpleLineListener);
}

public Clip getClip() {
Expand All @@ -51,6 +47,10 @@ public AudioInputStream getAudioInputStream() {
return audioInputStream;
}

public SimpleLineListener getSimpleLineListener() {
return simpleLineListener;
}

public void setLoopPoints(int loopStart, int loopEnd) {
clip.setLoopPoints(loopStart, loopEnd);
}
Expand Down
27 changes: 19 additions & 8 deletions src/main/java/tech/fastj/systems/audio/AudioManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import tech.fastj.engine.CrashMessages;
import tech.fastj.engine.FastJEngine;
import tech.fastj.math.Maths;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
Expand All @@ -10,24 +11,34 @@
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class AudioManager {

private static final ExecutorService AudioPlayer = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors() / 4, 1));
private static final int MinimumAudioThreads = 1;
private static final int MaximumAudioThreads = 4;
private static final ExecutorService AudioPlayer = Executors.newFixedThreadPool(
Maths.withinIntegerRange(
Runtime.getRuntime().availableProcessors(),
MinimumAudioThreads,
MaximumAudioThreads
)
);

private static final Map<String, Audio> AudioFiles = new HashMap<>();

public static void loadAudio(URL... audioPaths) {
for (URL audioPath : audioPaths) {
AudioFiles.put(audioPath.getPath(), new Audio(audioPath));
public static void loadAudio(Path... audioPaths) {
for (Path audioPath : audioPaths) {
AudioFiles.put(audioPath.toString(), new Audio(audioPath));
}
}

public static Audio getAudio(URL audioPath) {
return getAudio(audioPath.getPath());
public static Audio getAudio(Path audioPath) {
return getAudio(audioPath.toString());
}

public static Audio getAudio(String audioPath) {
Expand All @@ -46,9 +57,9 @@ static Clip newClip() {
}
}

static AudioInputStream newAudioStream(URL audioPath) {
static AudioInputStream newAudioStream(Path audioPath) {
try {
return AudioSystem.getAudioInputStream(audioPath);
return AudioSystem.getAudioInputStream(audioPath.toFile());
} catch (UnsupportedAudioFileException | IOException exception) {
FastJEngine.error(
CrashMessages.theGameCrashed("an error while loading sound."),
Expand Down
61 changes: 59 additions & 2 deletions src/main/java/tech/fastj/systems/audio/SimpleLineListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,64 @@
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;

public abstract class SimpleAudioListener implements LineListener {
public class SimpleLineListener implements LineListener {

private Runnable lineOpenAction;
private Runnable lineCloseAction;
private Runnable lineStartAction;
private Runnable lineStopAction;

public SimpleLineListener(Runnable lineOpenAction, Runnable lineCloseAction, Runnable lineStartAction, Runnable lineStopAction) {
this.lineOpenAction = lineOpenAction;
this.lineCloseAction = lineCloseAction;
this.lineStartAction = lineStartAction;
this.lineStopAction = lineStopAction;
}

public Runnable getLineOpenAction() {
return lineOpenAction;
}

public Runnable getLineCloseAction() {
return lineCloseAction;
}

public Runnable getLineStartAction() {
return lineStartAction;
}

public Runnable getLineStopAction() {
return lineStopAction;
}

public void setLineOpenAction(Runnable lineOpenAction) {
this.lineOpenAction = lineOpenAction;
}

public void setLineCloseAction(Runnable lineCloseAction) {
this.lineCloseAction = lineCloseAction;
}

public void setLineStartAction(Runnable lineStartAction) {
this.lineStartAction = lineStartAction;
}

public void setLineStopAction(Runnable lineStopAction) {
this.lineStopAction = lineStopAction;
}

@Override
public abstract void update(LineEvent event);
public void update(LineEvent event) {
LineEvent.Type lineEventType = event.getType();

if (LineEvent.Type.OPEN.equals(lineEventType)) {
lineOpenAction.run();
} else if (LineEvent.Type.CLOSE.equals(lineEventType)) {
lineCloseAction.run();
} else if (LineEvent.Type.START.equals(lineEventType)) {
lineStartAction.run();
} else if (LineEvent.Type.STOP.equals(lineEventType)) {
lineStopAction.run();
}
}
}

0 comments on commit 87d138f

Please sign in to comment.