mirror of
https://github.com/badvision/jace.git
synced 2024-11-28 10:52:33 +00:00
Went through the sound generation with a fine-tooth comb and made it sound a lot better!
This commit is contained in:
parent
11b26305f8
commit
45f56756e4
@ -33,6 +33,7 @@ import jace.hardware.mockingboard.R6522;
|
|||||||
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;
|
||||||
|
import java.util.concurrent.locks.LockSupport;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
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;
|
||||||
@ -184,6 +185,7 @@ public class CardMockingboard extends Card implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isRunning() && !pause) {
|
if (isRunning() && !pause) {
|
||||||
|
// buildMixerTable();
|
||||||
timerSync.lock();
|
timerSync.lock();
|
||||||
try {
|
try {
|
||||||
ticksSinceLastPlayback++;
|
ticksSinceLastPlayback++;
|
||||||
@ -246,13 +248,13 @@ public class CardMockingboard extends Card implements Runnable {
|
|||||||
out = out * 2.0 / 3.0 / numChips;
|
out = out * 2.0 / 3.0 / numChips;
|
||||||
double delta = 1.15;
|
double delta = 1.15;
|
||||||
for (int i = 15; i > 0; i--) {
|
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.188502227; /* = 10 ^ (1.5/20) = 1.5dB */
|
||||||
// out /= 1.15; /* = 10 ^ (3/20) = 3dB */
|
// out /= 1.15; /* = 10 ^ (3/20) = 3dB */
|
||||||
|
// delta += 0.0225;
|
||||||
delta += 0.0225;
|
// out /= delta; // As per applewin's source, the levels don't scale as documented.
|
||||||
out /= delta; // As per applewin's source, the levels don't scale as documented.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VolTable[0] = 0;
|
VolTable[0] = 0;
|
||||||
}
|
}
|
||||||
Thread playbackThread = null;
|
Thread playbackThread = null;
|
||||||
@ -321,74 +323,75 @@ public class CardMockingboard extends Card implements Runnable {
|
|||||||
ticksSinceLastPlayback = 0;
|
ticksSinceLastPlayback = 0;
|
||||||
int zeroSamples = 0;
|
int zeroSamples = 0;
|
||||||
setRun(true);
|
setRun(true);
|
||||||
|
LockSupport.parkNanos(5000);
|
||||||
while (isRunning()) {
|
while (isRunning()) {
|
||||||
while (!computer.isRunning()) {
|
while (isRunning() && !computer.isRunning()) {
|
||||||
Thread.sleep(500);
|
Thread.currentThread().yield();
|
||||||
}
|
}
|
||||||
computer.getMotherboard().requestSpeed(this);
|
if (isRunning()) {
|
||||||
playSound(leftBuffer, rightBuffer);
|
computer.getMotherboard().requestSpeed(this);
|
||||||
int p = 0;
|
playSound(leftBuffer, rightBuffer);
|
||||||
for (int idx = 0; idx < BUFFER_LENGTH; idx++) {
|
int p = 0;
|
||||||
int sampleL = leftBuffer[idx];
|
for (int idx = 0; idx < BUFFER_LENGTH; idx++) {
|
||||||
int sampleR = rightBuffer[idx];
|
int sampleL = leftBuffer[idx];
|
||||||
// Convert left + right samples into buffer format
|
int sampleR = rightBuffer[idx];
|
||||||
if (sampleL == 0 && sampleR == 0) {
|
// Convert left + right samples into buffer format
|
||||||
zeroSamples++;
|
if (sampleL == 0 && sampleR == 0) {
|
||||||
} else {
|
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;
|
zeroSamples = 0;
|
||||||
}
|
pause = true;
|
||||||
for (int shift = SoundMixer.BITS - 8, index = 0; shift >= 0; shift -= 8, index++) {
|
computer.getMotherboard().cancelSpeedRequest(this);
|
||||||
buffer[p + index] = (byte) (sampleR >> shift);
|
while (pause && isRunning()) {
|
||||||
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 {
|
|
||||||
try {
|
try {
|
||||||
timerSync.unlock();
|
Thread.sleep(50);
|
||||||
|
timerSync.lock();
|
||||||
|
playbackFinished.signalAll();
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
return;
|
||||||
} catch (IllegalMonitorStateException ex) {
|
} 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 {
|
||||||
try {
|
timerSync.lock();
|
||||||
timerSync.lock();
|
playbackFinished.signalAll();
|
||||||
playbackFinished.signalAll();
|
while (isRunning() && ticksSinceLastPlayback < ticksBeteenPlayback) {
|
||||||
while (isRunning() && ticksSinceLastPlayback < ticksBeteenPlayback) {
|
cpuCountReached.await();
|
||||||
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) {
|
} catch (LineUnavailableException ex) {
|
||||||
Logger.getLogger(CardMockingboard.class
|
Logger.getLogger(CardMockingboard.class
|
||||||
.getName()).log(Level.SEVERE, null, ex);
|
.getName()).log(Level.SEVERE, null, ex);
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
Logger.getLogger(CardMockingboard.class.getName()).log(Level.SEVERE, null, ex);
|
|
||||||
} finally {
|
} finally {
|
||||||
computer.getMotherboard().cancelSpeedRequest(this);
|
computer.getMotherboard().cancelSpeedRequest(this);
|
||||||
System.out.println("Mockingboard playback stopped");
|
System.out.println("Mockingboard playback stopped");
|
||||||
|
@ -32,6 +32,11 @@ public class EnvelopeGenerator extends TimedGenerator {
|
|||||||
int direction;
|
int direction;
|
||||||
int amplitude;
|
int amplitude;
|
||||||
|
|
||||||
|
boolean start1high = false;
|
||||||
|
boolean start2high = false;
|
||||||
|
boolean oneShot = false;
|
||||||
|
boolean oddEven = false;
|
||||||
|
|
||||||
public EnvelopeGenerator(int _clock, int _sampleRate) {
|
public EnvelopeGenerator(int _clock, int _sampleRate) {
|
||||||
super(_clock, _sampleRate);
|
super(_clock, _sampleRate);
|
||||||
}
|
}
|
||||||
@ -50,55 +55,54 @@ public class EnvelopeGenerator extends TimedGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int effectiveAmplitude = 0;
|
||||||
public void step() {
|
public void step() {
|
||||||
int stateChanges = updateCounter();
|
int stateChanges = updateCounter();
|
||||||
|
int total = 0;
|
||||||
for (int i = 0; i < stateChanges; i++) {
|
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;
|
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) {
|
public void setShape(int shape) {
|
||||||
|
oddEven = false;
|
||||||
counter = 0;
|
counter = 0;
|
||||||
cont = (shape & 8) != 0;
|
cont = (shape & 8) != 0;
|
||||||
attk = (shape & 4) != 0;
|
attk = (shape & 4) != 0;
|
||||||
alt = (shape & 2) != 0;
|
alt = (shape & 2) != 0;
|
||||||
hold = (shape & 1) != 0;
|
hold = ((shape ^ 8) & 9) != 0;
|
||||||
if (attk) {
|
|
||||||
|
start1high = !attk;
|
||||||
|
start2high = cont && ! (attk ^ alt ^ hold);
|
||||||
|
|
||||||
|
setPhase(start1high);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhase(boolean isHigh) {
|
||||||
|
if (isHigh) {
|
||||||
|
amplitude = 15;
|
||||||
|
direction = -1;
|
||||||
|
} else {
|
||||||
amplitude = 0;
|
amplitude = 0;
|
||||||
direction = 1;
|
direction = 1;
|
||||||
} else {
|
}
|
||||||
amplitude = 15;
|
}
|
||||||
direction = -1;
|
|
||||||
}
|
public int getEffectiveAmplitude() {
|
||||||
|
return effectiveAmplitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAmplitude() {
|
public int getAmplitude() {
|
||||||
|
@ -30,7 +30,7 @@ public class NoiseGenerator extends TimedGenerator {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int stepsPerCycle() {
|
public int stepsPerCycle() {
|
||||||
return 8;
|
return 4;
|
||||||
}
|
}
|
||||||
public void step() {
|
public void step() {
|
||||||
int stateChanges = updateCounter();
|
int stateChanges = updateCounter();
|
||||||
@ -39,11 +39,14 @@ public class NoiseGenerator extends TimedGenerator {
|
|||||||
}
|
}
|
||||||
public static final int BIT17 = 0x010000;
|
public static final int BIT17 = 0x010000;
|
||||||
public void updateRng() {
|
public void updateRng() {
|
||||||
// noise = (noise >> 1) ^ ((noise & 1) ? 0x14000 : 0);
|
rng = ((rng & 1) != 0 ? rng ^ 0x24000 : rng) >> 1;
|
||||||
int newBit17 = (rng & 0x04) > 0 == (rng & 0x01) > 0 ? BIT17 : 0;
|
if ((rng & 1) == 1) {
|
||||||
rng = newBit17 + (rng >> 1);
|
state = !state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean state = false;
|
||||||
public boolean isOn() {
|
public boolean isOn() {
|
||||||
return ((rng & 1) == 1);
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -58,16 +58,11 @@ public class SoundGenerator extends TimedGenerator {
|
|||||||
public int step(NoiseGenerator noiseGen, EnvelopeGenerator envGen) {
|
public int step(NoiseGenerator noiseGen, EnvelopeGenerator envGen) {
|
||||||
int stateChanges = updateCounter();
|
int stateChanges = updateCounter();
|
||||||
if (((stateChanges & 1) == 1)) inverted = !inverted;
|
if (((stateChanges & 1) == 1)) inverted = !inverted;
|
||||||
if (amplitude == 0 && !useEnvGen) return 0;
|
double amp = stateChanges == 0 ? 1 : 1.0 / Math.max(stateChanges-1, 1);
|
||||||
if (!active && !noiseActive) return 0;
|
int vol = useEnvGen ? envGen.getEffectiveAmplitude() : amplitude;
|
||||||
boolean invert;
|
boolean on = noiseActive && noiseGen.isOn() || (active && inverted);
|
||||||
int vol = useEnvGen ? envGen.getAmplitude() : amplitude;
|
// return invert ? -CardMockingboard.VolTable[vol] : CardMockingboard.VolTable[vol];
|
||||||
if (active) {
|
return on ? (int) (CardMockingboard.VolTable[vol] * amp) : 0;
|
||||||
invert = noiseActive && noiseGen.isOn() ? false : inverted;
|
|
||||||
} else {
|
|
||||||
invert = noiseActive && !noiseGen.isOn();
|
|
||||||
}
|
|
||||||
return invert ? -CardMockingboard.VolTable[vol] : CardMockingboard.VolTable[vol];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user