Went through the sound generation with a fine-tooth comb and made it sound a lot better!

This commit is contained in:
Brendan Robert 2015-09-06 00:47:58 -05:00
parent 11b26305f8
commit 45f56756e4
4 changed files with 113 additions and 108 deletions

View File

@ -33,6 +33,7 @@ import jace.hardware.mockingboard.R6522;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -184,6 +185,7 @@ public class CardMockingboard extends Card implements Runnable {
}
if (isRunning() && !pause) {
// buildMixerTable();
timerSync.lock();
try {
ticksSinceLastPlayback++;
@ -246,13 +248,13 @@ public class CardMockingboard extends Card implements Runnable {
out = out * 2.0 / 3.0 / numChips;
double delta = 1.15;
for (int i = 15; i > 0; i--) {
VolTable[i] = (int) Math.round(out); /* round to nearest */ // [TC: unsigned int cast]
VolTable[i] = (int) (out / Math.pow(Math.sqrt(2),(15-i)));
// out /= 1.188502227; /* = 10 ^ (1.5/20) = 1.5dB */
// out /= 1.15; /* = 10 ^ (3/20) = 3dB */
delta += 0.0225;
out /= delta; // As per applewin's source, the levels don't scale as documented.
// delta += 0.0225;
// out /= delta; // As per applewin's source, the levels don't scale as documented.
}
VolTable[0] = 0;
}
Thread playbackThread = null;
@ -321,74 +323,75 @@ public class CardMockingboard extends Card implements Runnable {
ticksSinceLastPlayback = 0;
int zeroSamples = 0;
setRun(true);
LockSupport.parkNanos(5000);
while (isRunning()) {
while (!computer.isRunning()) {
Thread.sleep(500);
while (isRunning() && !computer.isRunning()) {
Thread.currentThread().yield();
}
computer.getMotherboard().requestSpeed(this);
playSound(leftBuffer, rightBuffer);
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 {
if (isRunning()) {
computer.getMotherboard().requestSpeed(this);
playSound(leftBuffer, rightBuffer);
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 {
timerSync.lock();
ticksSinceLastPlayback -= ticksBeteenPlayback;
} finally {
timerSync.unlock();
}
out.write(buffer, 0, buffer.length);
if (zeroSamples >= MAX_IDLE_SAMPLES) {
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 {
timerSync.lock();
ticksSinceLastPlayback -= ticksBeteenPlayback;
} finally {
timerSync.unlock();
}
out.write(buffer, 0, buffer.length);
if (zeroSamples >= MAX_IDLE_SAMPLES) {
zeroSamples = 0;
pause = true;
computer.getMotherboard().cancelSpeedRequest(this);
while (pause && isRunning()) {
try {
Thread.sleep(50);
timerSync.lock();
playbackFinished.signalAll();
} catch (InterruptedException ex) {
return;
} catch (IllegalMonitorStateException ex) {
// Do nothing
} finally {
pause = true;
computer.getMotherboard().cancelSpeedRequest(this);
while (pause && isRunning()) {
try {
timerSync.unlock();
Thread.sleep(50);
timerSync.lock();
playbackFinished.signalAll();
} catch (InterruptedException ex) {
return;
} catch (IllegalMonitorStateException ex) {
// Do nothing -- this is probably caused by a suspension event
// Do nothing
} finally {
try {
timerSync.unlock();
} catch (IllegalMonitorStateException ex) {
// Do nothing -- this is probably caused by a suspension event
}
}
}
}
}
try {
timerSync.lock();
playbackFinished.signalAll();
while (isRunning() && ticksSinceLastPlayback < ticksBeteenPlayback) {
cpuCountReached.await();
try {
timerSync.lock();
playbackFinished.signalAll();
while (isRunning() && ticksSinceLastPlayback < ticksBeteenPlayback) {
cpuCountReached.await();
}
} catch (InterruptedException ex) {
// Do nothing, probably killing playback thread on purpose
} finally {
timerSync.unlock();
}
} catch (InterruptedException ex) {
// Do nothing, probably killing playback thread on purpose
} finally {
timerSync.unlock();
}
}
} catch (LineUnavailableException ex) {
Logger.getLogger(CardMockingboard.class
.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(CardMockingboard.class.getName()).log(Level.SEVERE, null, ex);
} finally {
computer.getMotherboard().cancelSpeedRequest(this);
System.out.println("Mockingboard playback stopped");

View File

@ -32,6 +32,11 @@ public class EnvelopeGenerator extends TimedGenerator {
int direction;
int amplitude;
boolean start1high = false;
boolean start2high = false;
boolean oneShot = false;
boolean oddEven = false;
public EnvelopeGenerator(int _clock, int _sampleRate) {
super(_clock, _sampleRate);
}
@ -50,55 +55,54 @@ public class EnvelopeGenerator extends TimedGenerator {
}
}
int effectiveAmplitude = 0;
public void step() {
int stateChanges = updateCounter();
int total = 0;
for (int i = 0; i < stateChanges; i++) {
if (amplitude == 0 && direction == -1) {
if (!cont) {
direction = 0;
} else if (hold) {
direction = 0;
if (alt) {
amplitude = 15;
}
} else if (alt) {
direction = 1;
} else {
amplitude = 15;
}
}
if (amplitude == 15 && direction == 1) {
if (!cont) {
direction = 0;
amplitude = 0;
} else if (hold) {
direction = 0;
if (alt) {
amplitude = 0;
}
} else if (alt) {
direction = -1;
} else {
amplitude = 0;
}
}
amplitude += direction;
if (amplitude > 15 || amplitude < 0) {
setPhase(oddEven ? start1high : start2high);
oddEven = !oddEven;
if (hold) {
direction = 0;
}
}
total += amplitude;
}
if (stateChanges == 0) {
effectiveAmplitude = amplitude;
} else {
effectiveAmplitude = Math.min(15, total / stateChanges);
}
}
public void setShape(int shape) {
oddEven = false;
counter = 0;
cont = (shape & 8) != 0;
attk = (shape & 4) != 0;
alt = (shape & 2) != 0;
hold = (shape & 1) != 0;
if (attk) {
hold = ((shape ^ 8) & 9) != 0;
start1high = !attk;
start2high = cont && ! (attk ^ alt ^ hold);
setPhase(start1high);
}
public void setPhase(boolean isHigh) {
if (isHigh) {
amplitude = 15;
direction = -1;
} else {
amplitude = 0;
direction = 1;
} else {
amplitude = 15;
direction = -1;
}
}
}
public int getEffectiveAmplitude() {
return effectiveAmplitude;
}
public int getAmplitude() {

View File

@ -30,7 +30,7 @@ public class NoiseGenerator extends TimedGenerator {
}
@Override
public int stepsPerCycle() {
return 8;
return 4;
}
public void step() {
int stateChanges = updateCounter();
@ -39,11 +39,14 @@ public class NoiseGenerator extends TimedGenerator {
}
public static final int BIT17 = 0x010000;
public void updateRng() {
// noise = (noise >> 1) ^ ((noise & 1) ? 0x14000 : 0);
int newBit17 = (rng & 0x04) > 0 == (rng & 0x01) > 0 ? BIT17 : 0;
rng = newBit17 + (rng >> 1);
rng = ((rng & 1) != 0 ? rng ^ 0x24000 : rng) >> 1;
if ((rng & 1) == 1) {
state = !state;
}
}
boolean state = false;
public boolean isOn() {
return ((rng & 1) == 1);
return state;
}
}

View File

@ -58,16 +58,11 @@ public class SoundGenerator extends TimedGenerator {
public int step(NoiseGenerator noiseGen, EnvelopeGenerator envGen) {
int stateChanges = updateCounter();
if (((stateChanges & 1) == 1)) inverted = !inverted;
if (amplitude == 0 && !useEnvGen) return 0;
if (!active && !noiseActive) return 0;
boolean invert;
int vol = useEnvGen ? envGen.getAmplitude() : amplitude;
if (active) {
invert = noiseActive && noiseGen.isOn() ? false : inverted;
} else {
invert = noiseActive && !noiseGen.isOn();
}
return invert ? -CardMockingboard.VolTable[vol] : CardMockingboard.VolTable[vol];
double amp = stateChanges == 0 ? 1 : 1.0 / Math.max(stateChanges-1, 1);
int vol = useEnvGen ? envGen.getEffectiveAmplitude() : amplitude;
boolean on = noiseActive && noiseGen.isOn() || (active && inverted);
// return invert ? -CardMockingboard.VolTable[vol] : CardMockingboard.VolTable[vol];
return on ? (int) (CardMockingboard.VolTable[vol] * amp) : 0;
}
@Override