Retrofit mockingboard playback to new LWGJL engine

This commit is contained in:
Brendan Robert 2023-10-24 18:46:10 -05:00
parent 5edaf8a69b
commit 64e5317019

View File

@ -18,6 +18,7 @@
*/ */
package jace.hardware; package jace.hardware;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
@ -26,8 +27,6 @@ import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.sound.sampled.SourceDataLine;
import jace.config.ConfigurableField; import jace.config.ConfigurableField;
import jace.config.Name; import jace.config.Name;
import jace.core.Card; import jace.core.Card;
@ -35,6 +34,7 @@ import jace.core.Computer;
import jace.core.Motherboard; import jace.core.Motherboard;
import jace.core.RAMEvent; import jace.core.RAMEvent;
import jace.core.RAMEvent.TYPE; import jace.core.RAMEvent.TYPE;
import jace.core.SoundMixer.SoundBuffer;
import jace.core.RAMListener; import jace.core.RAMListener;
import jace.core.SoundMixer; import jace.core.SoundMixer;
import jace.hardware.mockingboard.PSG; import jace.hardware.mockingboard.PSG;
@ -254,8 +254,6 @@ public class CardMockingboard extends Card implements Runnable {
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
public static int[] VolTable; public static int[] VolTable;
int[][] buffers;
int bufferLength = -1;
public void playSound(int[] left, int[] right) { public void playSound(int[] left, int[] right) {
chips[0].update(left, true, left, false, left, false, BUFFER_LENGTH); chips[0].update(left, true, left, false, left, false, BUFFER_LENGTH);
@ -346,19 +344,16 @@ public class CardMockingboard extends Card implements Runnable {
* This is the audio playback thread * This is the audio playback thread
*/ */
public void run() { public void run() {
SourceDataLine out = null; SoundBuffer buffer = SoundMixer.createBuffer(true);
try { try {
// out = computer.mixer.getLine(); if (buffer == null) {
if (out == null) {
setRun(false); setRun(false);
return; return;
} }
int[] leftBuffer = new int[BUFFER_LENGTH];
int[] rightBuffer = new int[BUFFER_LENGTH];
int frameSize = out.getFormat().getFrameSize();
byte[] buffer = new byte[BUFFER_LENGTH * frameSize];
System.out.println("Mockingboard playback started"); System.out.println("Mockingboard playback started");
int bytesPerSample = frameSize / 2; int bufferSize = SoundMixer.BUFFER_SIZE;
int[] left = new int[bufferSize];
int[] right = new int[bufferSize];
buildMixerTable(); buildMixerTable();
ticksBetweenPlayback = (int) ((Motherboard.DEFAULT_SPEED * BUFFER_LENGTH) / SAMPLE_RATE); ticksBetweenPlayback = (int) ((Motherboard.DEFAULT_SPEED * BUFFER_LENGTH) / SAMPLE_RATE);
System.out.println("Ticks between playback: "+ticksBetweenPlayback); System.out.println("Ticks between playback: "+ticksBetweenPlayback);
@ -371,30 +366,27 @@ public class CardMockingboard extends Card implements Runnable {
Thread.sleep(1000); Thread.sleep(1000);
} }
if (isRunning() && !Thread.interrupted()) { if (isRunning() && !Thread.interrupted()) {
playSound(leftBuffer, rightBuffer); playSound(left, right);
int p = 0;
for (int idx = 0; idx < BUFFER_LENGTH; idx++) {
int sampleL = leftBuffer[idx];
int sampleR = rightBuffer[idx];
// Convert left + right samples into buffer format
if (sampleL == 0 && sampleR == 0) {
zeroSamples++;
} else {
zeroSamples = 0;
}
for (int shift = SoundMixer.BITS - 8, index = 0; shift >= 0; shift -= 8, index++) {
buffer[p + index] = (byte) (sampleR >> shift);
buffer[p + index + bytesPerSample] = (byte) (sampleL >> shift);
}
p += frameSize;
}
try { try {
for (int i=0; i < bufferSize; i++) {
buffer.playSample((short) left[i]);
buffer.playSample((short) right[i]);
}
timerSync.lock(); timerSync.lock();
ticksSinceLastPlayback -= ticksBetweenPlayback; ticksSinceLastPlayback -= ticksBetweenPlayback;
} catch (ExecutionException e) {
Logger.getLogger(CardMockingboard.class.getName()).log(Level.SEVERE, "Mockingboard playback encountered fatal exception", e);
try {
buffer.shutdown();
} catch (ExecutionException e1) {
// Ignore shutdown errors, we're already reporting a fatal error
}
buffer=null;
setRun(false);
break;
} finally { } finally {
timerSync.unlock(); timerSync.unlock();
} }
out.write(buffer, 0, buffer.length);
if (zeroSamples >= MAX_IDLE_SAMPLES) { if (zeroSamples >= MAX_IDLE_SAMPLES) {
zeroSamples = 0; zeroSamples = 0;
pause = true; pause = true;
@ -437,9 +429,12 @@ public class CardMockingboard extends Card implements Runnable {
} finally { } finally {
computer.getMotherboard().cancelSpeedRequest(this); computer.getMotherboard().cancelSpeedRequest(this);
System.out.println("Mockingboard playback stopped"); System.out.println("Mockingboard playback stopped");
if (out != null && out.isRunning()) { if (buffer != null && buffer.isAlive()) {
out.drain(); try {
out.close(); buffer.shutdown();
} catch (InterruptedException | ExecutionException e) {
// Ignore errors during shutdown
}
} }
} }
} }