Partial attempt at getting Mockingboard to run more correctly, start of rewrite of music playback routines

This commit is contained in:
Brendan Robert
2023-10-24 21:54:34 -05:00
parent 64e5317019
commit 6d271362b2
8 changed files with 84 additions and 24 deletions

View File

@@ -198,7 +198,6 @@ public class SoundMixer extends Device {
Logger.getLogger(SoundMixer.class.getName()).warning("Playback attempted on stopped buffer!"); Logger.getLogger(SoundMixer.class.getName()).warning("Playback attempted on stopped buffer!");
return; return;
} }
currentBuffer.put(sample);
if (!currentBuffer.hasRemaining()) { if (!currentBuffer.hasRemaining()) {
buffersGenerated++; buffersGenerated++;
currentBuffer.flip(); currentBuffer.flip();
@@ -232,6 +231,7 @@ public class SoundMixer extends Device {
currentBuffer = alternateBuffer; currentBuffer = alternateBuffer;
alternateBuffer = tempBuffer; alternateBuffer = tempBuffer;
} }
currentBuffer.put(sample);
} }
public void shutdown() throws InterruptedException, ExecutionException { public void shutdown() throws InterruptedException, ExecutionException {

View File

@@ -108,7 +108,7 @@ public abstract class TimedDevice extends Device {
if (worker != null && worker.isAlive()) { if (worker != null && worker.isAlive()) {
return; return;
} }
worker = new Thread(() -> { Thread newWorker = new Thread(() -> {
// System.out.println("Worker thread for " + getDeviceName() + " starting"); // System.out.println("Worker thread for " + getDeviceName() + " starting");
while (isRunning()) { while (isRunning()) {
hasStopped = false; hasStopped = false;
@@ -124,10 +124,11 @@ public abstract class TimedDevice extends Device {
hasStopped = true; hasStopped = true;
// System.out.println("Worker thread for " + getDeviceName() + " stopped"); // System.out.println("Worker thread for " + getDeviceName() + " stopped");
}); });
worker.setDaemon(false); this.worker = newWorker;
worker.setPriority(Thread.MAX_PRIORITY); newWorker.setDaemon(false);
worker.start(); newWorker.setPriority(Thread.MAX_PRIORITY);
worker.setName("Timed device " + getDeviceName() + " worker"); newWorker.setName("Timed device " + getDeviceName() + " worker");
newWorker.start();
} }
long nanosPerInterval; // How long to wait between pauses long nanosPerInterval; // How long to wait between pauses
long cyclesPerInterval; // How many cycles to wait until a pause interval long cyclesPerInterval; // How many cycles to wait until a pause interval

View File

@@ -324,14 +324,13 @@ public class CardMockingboard extends Card implements Runnable {
} }
public boolean suspendSound() { public boolean suspendSound() {
setRun(false);
if (playbackThread == null || !playbackThread.isAlive()) { if (playbackThread == null || !playbackThread.isAlive()) {
return false; return false;
} }
if (playbackThread != null) { if (playbackThread != null) {
playbackThread.interrupt();
try { try {
// Wait for thread to die playbackThread.join(500);
playbackThread.join();
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }

View File

@@ -160,6 +160,9 @@ public class LawlessComputer extends Apple2e {
} }
public void waitForVBL(int count) throws InterruptedException { public void waitForVBL(int count) throws InterruptedException {
if (!isRunning()) {
return;
}
Semaphore s = new Semaphore(0); Semaphore s = new Semaphore(0);
onNextVBL(s::release); onNextVBL(s::release);
s.acquire(); s.acquire();

View File

@@ -18,9 +18,6 @@ import jace.cheat.Cheats;
import jace.core.Computer; import jace.core.Computer;
import jace.core.RAMEvent; import jace.core.RAMEvent;
import jace.lawless.LawlessVideo.RenderEngine; import jace.lawless.LawlessVideo.RenderEngine;
import javafx.beans.property.DoubleProperty;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration; import javafx.util.Duration;
/** /**
@@ -50,12 +47,10 @@ public class LawlessHacks extends Cheats {
addCheat("Lawless Legends Graphics Modes", RAMEvent.TYPE.ANY, (e) -> { addCheat("Lawless Legends Graphics Modes", RAMEvent.TYPE.ANY, (e) -> {
int addr = e.getAddress(); int addr = e.getAddress();
if (addr >= MODE_SOFTSWITCH_MIN && e.getAddress() <= MODE_SOFTSWITCH_MAX) { if (addr >= MODE_SOFTSWITCH_MIN && e.getAddress() <= MODE_SOFTSWITCH_MAX) {
// System.out.println("Trapped " + e.getType().toString() + " to $" + Integer.toHexString(e.getAddress()));
setEngineByOrdinal(e.getAddress() - MODE_SOFTSWITCH_MIN); setEngineByOrdinal(e.getAddress() - MODE_SOFTSWITCH_MIN);
} }
}, MODE_SOFTSWITCH_MIN, MODE_SOFTSWITCH_MAX); }, MODE_SOFTSWITCH_MIN, MODE_SOFTSWITCH_MAX);
addCheat("Lawless Legends Music Commands", RAMEvent.TYPE.WRITE, (e) -> { addCheat("Lawless Legends Music Commands", RAMEvent.TYPE.WRITE, (e) -> {
// System.out.println(Integer.toHexString(e.getAddress()) + " => " + Integer.toHexString(e.getNewValue() & 0x0ff));
playSound(e.getNewValue()); playSound(e.getNewValue());
}, SFX_TRIGGER); }, SFX_TRIGGER);
} }
@@ -165,7 +160,7 @@ public class LawlessHacks extends Cheats {
playbackEffect = null; playbackEffect = null;
} }
private Optional<Double> getCurrentTime() { private Optional<Long> getCurrentTime() {
if (currentSongPlayer == null) { if (currentSongPlayer == null) {
return Optional.empty(); return Optional.empty();
} else if (currentSongPlayer.getCurrentTime() == null) { } else if (currentSongPlayer.getCurrentTime() == null) {
@@ -181,9 +176,8 @@ public class LawlessHacks extends Cheats {
if (player != null) { if (player != null) {
getCurrentTime().ifPresent(val -> lastTime.put(currentSong, val + 1500)); getCurrentTime().ifPresent(val -> lastTime.put(currentSong, val + 1500));
playbackEffect = new Thread(() -> { playbackEffect = new Thread(() -> {
DoubleProperty volume = player.volumeProperty(); while (playbackEffect == Thread.currentThread() && player.getVolume() > 0.0) {
while (playbackEffect == Thread.currentThread() && volume.get() > 0.0) { player.setVolume(player.getVolume() - FADE_AMT);
volume.set(volume.get() - FADE_AMT);
try { try {
Thread.sleep(FADE_SPEED); Thread.sleep(FADE_SPEED);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@@ -208,14 +202,13 @@ public class LawlessHacks extends Cheats {
private void fadeInSong(MediaPlayer player) { private void fadeInSong(MediaPlayer player) {
stopSongEffect(); stopSongEffect();
currentSongPlayer = player; currentSongPlayer = player;
DoubleProperty volume = player.volumeProperty(); if (player.getVolume() >= 1.0) {
if (volume.get() >= 1.0) {
return; return;
} }
playbackEffect = new Thread(() -> { playbackEffect = new Thread(() -> {
while (playbackEffect == Thread.currentThread() && volume.get() < 1.0) { while (playbackEffect == Thread.currentThread() && player.getVolume() < 1.0) {
volume.set(volume.get() + FADE_AMT); player.setVolume(player.getVolume() + FADE_AMT);
try { try {
Thread.sleep(FADE_SPEED); Thread.sleep(FADE_SPEED);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@@ -250,7 +243,7 @@ public class LawlessHacks extends Cheats {
player.setCycleCount(repeatSong ? MediaPlayer.INDEFINITE : 1); player.setCycleCount(repeatSong ? MediaPlayer.INDEFINITE : 1);
player.setVolume(0.0); player.setVolume(0.0);
if (playingFightSong || autoResume.contains(track) || switchScores) { if (playingFightSong || autoResume.contains(track) || switchScores) {
double time = lastTime.getOrDefault(track, 0.0); long time = lastTime.getOrDefault(track, 0L);
System.out.println("Auto-resume from time " + time); System.out.println("Auto-resume from time " + time);
player.setStartTime(Duration.millis(time)); player.setStartTime(Duration.millis(time));
} }
@@ -316,7 +309,7 @@ public class LawlessHacks extends Cheats {
Pattern ENTRY = Pattern.compile("([0-9]+)\\s+(.*)"); Pattern ENTRY = Pattern.compile("([0-9]+)\\s+(.*)");
private final Map<String, Map<Integer, String>> scores = new HashMap<>(); private final Map<String, Map<Integer, String>> scores = new HashMap<>();
private final Set<Integer> autoResume = new HashSet<>(); private final Set<Integer> autoResume = new HashSet<>();
private final Map<Integer, Double> lastTime = new HashMap<>(); private final Map<Integer, Long> lastTime = new HashMap<>();
private void readScores() { private void readScores() {
InputStream data = getClass().getResourceAsStream("/jace/data/sound/scores.txt"); InputStream data = getClass().getResourceAsStream("/jace/data/sound/scores.txt");
readScores(data); readScores(data);

View File

@@ -0,0 +1,8 @@
package jace.lawless;
public class Media {
public Media(String resourcePath) {
}
}

View File

@@ -0,0 +1,55 @@
package jace.lawless;
import java.time.Duration;
public class MediaPlayer {
double vol = 1.0;
int repeats = 0;
int maxRepetitions = 1;
Status status = Status.STOPPED;
public static enum Status {
PLAYING, PAUSED, STOPPED
}
public static final int INDEFINITE = -1;
public MediaPlayer(Media song) {
}
public Status getStatus() {
return null;
}
public Duration getCurrentTime() {
return null;
}
public double getVolume() {
return vol;
}
public void stop() {
status = Status.STOPPED;
}
public void setCycleCount(int i) {
maxRepetitions = i;
}
public void setVolume(double d) {
vol = Math.max(0.0, Math.min(1.0, d));
}
public void setStartTime(javafx.util.Duration millis) {
}
public void play() {
repeats = 0;
status = Status.PLAYING;
}
}

View File

@@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
@SuppressWarnings("all")
module lawlesslegends { module lawlesslegends {
requires nestedvm; requires nestedvm;
requires java.base; requires java.base;