Tweaks to timing/speaker sound, visual sound debug feature added

This commit is contained in:
Brendan Robert 2024-04-23 10:08:38 -05:00
parent 4946dbd1e9
commit 24fd496d31
7 changed files with 61 additions and 23 deletions

View File

@ -52,6 +52,9 @@ public class Speaker extends Device {
@ConfigurableField(category = "sound", name = "1mhz timing", description = "Force speaker output to 1mhz?")
public static boolean force1mhz = true;
@ConfigurableField(category = "sound", name = "Show sound", description = "Use black color value to show sound output")
public static boolean showSound = false;
@InvokableAction(category = "sound", name = "Record sound", description="Toggles recording (saving) sound output to a file", defaultKeyMapping = "ctrl+shift+w")
public static void toggleFileOutput() {
if (fileOutputActive) {
@ -95,20 +98,23 @@ public class Speaker extends Device {
*/
@ConfigurableField(name = "Speaker Volume", shortName = "vol", description = "Should be under 1400")
public static int VOLUME = 400;
/**
* Number of idle cycles until speaker playback is deactivated
*/
@ConfigurableField(name = "Idle cycles before sleep", shortName = "idle")
public static int MAX_IDLE_CYCLES = 2000000;
private int currentVolume = 0;
private int fadeOffAmount = 1;
/**
* Manifestation of the apple speaker softswitch
*/
private boolean speakerBit = false;
private double TICKS_PER_SAMPLE = ((double) TimedDevice.NTSC_1MHZ) / SoundMixer.RATE;
private double TICKS_PER_SAMPLE_FLOOR = Math.floor(TICKS_PER_SAMPLE);
private static double TICKS_PER_SAMPLE = ((double) TimedDevice.NTSC_1MHZ) / SoundMixer.RATE;
private RAMListener listener = null;
private SoundBuffer buffer = null;
/**
* Number of idle cycles until speaker playback is deactivated
*/
@ConfigurableField(name = "Idle cycles before sleep", shortName = "idle")
// public static int MAX_IDLE_CYCLES = (int) (SoundMixer.BUFFER_SIZE * TICKS_PER_SAMPLE * 2);
public static int MAX_IDLE_CYCLES = (int) TimedDevice.NTSC_1MHZ / 4;
/**
* Suspend playback of sound
*
@ -118,7 +124,6 @@ public class Speaker extends Device {
public boolean suspend() {
boolean result = super.suspend();
speakerBit = false;
Emulator.withComputer(c->c.getMotherboard().cancelSpeedRequest(this));
if (buffer != null) {
try {
buffer.shutdown();
@ -128,6 +133,7 @@ public class Speaker extends Device {
buffer = null;
}
}
Emulator.withComputer(c->c.getMotherboard().cancelSpeedRequest(this));
return result;
}
@ -164,7 +170,6 @@ public class Speaker extends Device {
} else {
TICKS_PER_SAMPLE = Emulator.withComputer(c-> ((double) c.getMotherboard().getSpeedInHz()) / SoundMixer.RATE, 0.0);
}
TICKS_PER_SAMPLE_FLOOR = Math.floor(TICKS_PER_SAMPLE);
super.resume();
}
@ -172,9 +177,9 @@ public class Speaker extends Device {
* Reset idle counter whenever sound playback occurs
*/
public void resetIdle() {
currentVolume = VOLUME;
idleCycles = 0;
if (!isRunning()) {
speakerBit = false;
resume();
}
}
@ -186,21 +191,32 @@ public class Speaker extends Device {
*/
@Override
public void tick() {
if (idleCycles++ >= MAX_IDLE_CYCLES) {
suspend();
}
if (speakerBit) {
level++;
if (showSound) {
VideoNTSC.CHANGE_BLACK_COLOR(40, 20, 20);
}
} else if (showSound) {
VideoNTSC.CHANGE_BLACK_COLOR(20,20,40);
}
if (idleCycles++ >= MAX_IDLE_CYCLES && (currentVolume <= 0 || !speakerBit)) {
suspend();
if (showSound) {
VideoNTSC.CHANGE_BLACK_COLOR(0,0,0);
}
}
counter += 1.0d;
if (counter >= TICKS_PER_SAMPLE) {
playSample(level * VOLUME);
Emulator.withComputer(c->c.getMotherboard().requestSpeed(this));
if (idleCycles >= MAX_IDLE_CYCLES) {
currentVolume -= fadeOffAmount;
}
playSample(level * currentVolume);
// Emulator.withComputer(c->c.getMotherboard().requestSpeed(this));
// Set level back to 0
level = 0;
// Set counter to 0
counter -= TICKS_PER_SAMPLE_FLOOR;
counter -= TICKS_PER_SAMPLE;
}
}

View File

@ -640,7 +640,7 @@ public class VideoDHGR extends Video {
Logger.getLogger(getClass().getName()).warning("Went out of bounds in video display");
}
}
static final Color BLACK = Color.BLACK;
static Color BLACK = Color.BLACK;
static Color WHITE = Color.WHITE;
static final int[][] XY_OFFSET;

View File

@ -27,6 +27,7 @@ import jace.config.InvokableAction;
import jace.core.Computer;
import jace.core.RAMEvent;
import jace.core.RAMListener;
import jace.core.Video;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
@ -331,6 +332,19 @@ public class VideoNTSC extends VideoDHGR {
{1.0, 0.0, 0.0}, //1111 f
};
public static void CHANGE_BLACK_COLOR(int r, int g, int b) {
Emulator.withVideo(v->{
VideoNTSC vntsc = (VideoNTSC) v;
BLACK = Color.rgb(r, g, b);
int c = colorToInt(BLACK);
for (int i1 = 0; i1 < 4; i1++) {
vntsc.SOLID_PALETTE[i1][0] = c;
vntsc.TEXT_PALETTE[i1][0] = c;
}
});
Video.forceRefresh();
}
private void initDivideTables() {
for (int i = 0; i < 560; i++) {
divBy28[i] = i / 28;
@ -361,10 +375,18 @@ public class VideoNTSC extends VideoDHGR {
}
static public int yiqToRgb(double y, double i, double q) {
return colorToInt(yiqToRgbColor(y, i, q));
}
static public Color yiqToRgbColor(double y, double i, double q) {
int r = (int) (normalize((y + 0.956 * i + 0.621 * q), 0, 1) * 255);
int g = (int) (normalize((y - 0.272 * i - 0.647 * q), 0, 1) * 255);
int b = (int) (normalize((y - 1.105 * i + 1.702 * q), 0, 1) * 255);
return (255 << 24) | (r << 16) | (g << 8) | b;
return Color.rgb(r, g, b);
}
static public int colorToInt(Color c) {
return (int) (255 << 24) | (int) (c.getRed() * 255) << 16 | (int) (c.getGreen() * 255) << 8 | (int) (c.getBlue() * 255);
}
public static double normalize(double x, double minX, double maxX) {

View File

@ -188,6 +188,8 @@ public abstract class TimedDevice extends Device {
return null;
}
cycleTimer = 0;
long retVal = nextSync;
nextSync = Math.max(nextSync, System.nanoTime()) + nanosPerInterval;
if (isMaxSpeed() || useParentTiming()) {
if (tempSpeedDuration > 0) {
tempSpeedDuration -= cyclesPerInterval;
@ -195,11 +197,8 @@ public abstract class TimedDevice extends Device {
disableTempMaxSpeed();
}
}
nextSync += nanosPerInterval;
return null;
}
long retVal = nextSync;
nextSync = Math.min(nextSync + nanosPerInterval, System.nanoTime() + nanosPerInterval * 2); // Avoid drift (but not too much!
return retVal;
}
}

View File

@ -274,7 +274,7 @@ public abstract class Video extends TimedDevice {
Emulator.withVideo(v->v._forceRefresh());
}
private void _forceRefresh() {
protected void _forceRefresh() {
lineDirty = true;
screenDirty = true;
forceRedrawRowCount = APPLE_SCREEN_LINES + 1;

View File

@ -426,7 +426,7 @@ public class CardAppleMouse extends Card {
* Described in Apple Mouse technical note #7
* Cn1A: Read mouse clamping values
* Register number is stored in $478 and ranges from x47 to x4e
* Return value should be stored in $5782
* Return value should be stored in $578
* Values should be returned in this order:
* MinXH, MinYH, MinXL, MinYL, MaxXH, MaxYH, MaxXL, MaxYL
*/

View File

@ -24,6 +24,7 @@ import jace.core.RAMListener;
/**
* Implements a basic hardware accelerator that is able to adjust the speed of the emulator
*/
// TODO: Support the registers used here: https://github.com/a2-4am/4cade/blob/main/src/hw.accel.a#L238
public class ZipWarpAccelerator extends Device {
@ConfigurableField(category = "debug", name = "Debug messages")
public boolean debugMessagesEnabled = false;