Almost fully figured out the synth format decoder

This commit is contained in:
Alex Iadicicco 2022-12-05 23:42:00 -08:00 committed by Alexis King
parent 13a7b96fab
commit 5840b1fa80
6 changed files with 428 additions and 417 deletions

View File

@ -4,7 +4,7 @@ import funorb.cache.ResourceLoader;
import funorb.io.Buffer;
public final class FmtSynth {
private final Oscillator[] oscs = new Oscillator[10];
private final Synth[] oscs = new Synth[10];
private final int loopStartMs;
private final int loopEndMs;
@ -13,7 +13,7 @@ public final class FmtSynth {
final int peekByte = data.readUByte();
if (peekByte != 0) {
--data.pos;
this.oscs[i] = new Oscillator();
this.oscs[i] = new Synth();
this.oscs[i].initialize(data);
}
}
@ -31,8 +31,8 @@ public final class FmtSynth {
int totalDurMs = 0;
for (int i = 0; i < 10; ++i) {
if (this.oscs[i] != null && totalDurMs < this.oscs[i].durMs + this.oscs[i].delayMs) {
totalDurMs = this.oscs[i].durMs + this.oscs[i].delayMs;
if (this.oscs[i] != null && totalDurMs < this.oscs[i].lengthMs + this.oscs[i].posMs) {
totalDurMs = this.oscs[i].lengthMs + this.oscs[i].posMs;
}
}
@ -44,9 +44,9 @@ public final class FmtSynth {
for (int i = 0; i < 10; ++i) {
if (this.oscs[i] != null) {
final int durSamples = this.oscs[i].durMs * SampledAudioChannel.SAMPLES_PER_SECOND / 1000;
final int delaySamples = this.oscs[i].delayMs * SampledAudioChannel.SAMPLES_PER_SECOND / 1000;
final int[] s16buf = this.oscs[i].generateS16(durSamples, this.oscs[i].durMs);
final int durSamples = this.oscs[i].lengthMs * SampledAudioChannel.SAMPLES_PER_SECOND / 1000;
final int delaySamples = this.oscs[i].posMs * SampledAudioChannel.SAMPLES_PER_SECOND / 1000;
final int[] s16buf = this.oscs[i].generateS16(durSamples, this.oscs[i].lengthMs);
for (int j = 0; j < durSamples; ++j) {
int sample = dataS8[j + delaySamples] + (s16buf[j] >> 8);

View File

@ -1,317 +0,0 @@
package funorb.audio;
import funorb.io.Buffer;
import java.util.Arrays;
import java.util.Random;
public final class Oscillator {
private static final int[] NOISE = new int[0x8000];
private static final int[] SINE = new int[0x8000];
private static final int[] buf;
private static final int[] _p;
private static final int[] _q;
private static final int[] _t;
private static final int[] _c;
private static final int[] _w;
static {
final Random var0 = new Random(0L);
for (int i = 0; i < 0x8000; ++i) {
NOISE[i] = (var0.nextInt() & 2) - 1;
}
for (int i = 0; i < 0x8000; ++i) {
SINE[i] = (int) (Math.sin((double) i * Math.PI / 0x4000) * 0x4000);
}
buf = new int[220500];
_q = new int[5];
_t = new int[5];
_p = new int[5];
_w = new int[5];
_c = new int[5];
}
private final int[] _y = new int[]{0, 0, 0, 0, 0};
private final int[] _x = new int[]{0, 0, 0, 0, 0};
private final int[] _h = new int[]{0, 0, 0, 0, 0};
public int delayMs = 0;
public int durMs = 500;
private fh_ _k;
private OscillatorState osc5_;
private int _f = 0;
private OscillatorState osc7_;
private OscillatorState osc4_;
private OscillatorState osc3_;
private OscillatorState osc0_;
private int _b = 100;
private OscillatorState osc8_;
private OscillatorState osc6_;
private OscillatorState osc2_;
private OscillatorState osc1_;
public int[] generateS16(final int len, final int lenMs) {
Arrays.fill(buf, 0, len, 0);
if (lenMs < 10) {
return buf;
}
final double samplesPerMs = (double) len / ((double) lenMs + 0.0D);
this.osc0_.reset();
this.osc1_.reset();
int var5 = 0;
int var6 = 0;
int var7 = 0;
if (this.osc2_ != null) {
this.osc2_.reset();
this.osc3_.reset();
var5 = (int) ((double) (this.osc2_._i - this.osc2_._d) * 32.768D / samplesPerMs);
var6 = (int) ((double) this.osc2_._d * 32.768D / samplesPerMs);
}
int var8 = 0;
int var9 = 0;
int var10 = 0;
if (this.osc4_ != null) {
this.osc4_.reset();
this.osc5_.reset();
var8 = (int) ((double) (this.osc4_._i - this.osc4_._d) * 32.768D / samplesPerMs);
var9 = (int) ((double) this.osc4_._d * 32.768D / samplesPerMs);
}
for (int i = 0; i < 5; ++i) {
if (this._y[i] != 0) {
_c[i] = 0;
_q[i] = (int) ((double) this._h[i] * samplesPerMs);
_p[i] = (this._y[i] << 14) / 100;
_t[i] = (int) ((double) (this.osc0_._i - this.osc0_._d) * 32.768D * Math.pow(1.0057929410678534D, this._x[i]) / samplesPerMs);
_w[i] = (int) ((double) this.osc0_._d * 32.768D / samplesPerMs);
}
}
for (int i = 0; i < len; ++i) {
int var12 = this.osc0_.next(len);
int var13 = this.osc1_.next(len);
int var14;
int var15;
if (this.osc2_ != null) {
var14 = this.osc2_.next(len);
var15 = this.osc3_.next(len);
var12 += this.sample(this.osc2_.waveform, var7, var15) >> 1;
var7 += (var14 * var5 >> 16) + var6;
}
if (this.osc4_ != null) {
var14 = this.osc4_.next(len);
var15 = this.osc5_.next(len);
var13 = var13 * ((this.sample(this.osc4_.waveform, var10, var15) >> 1) + 0x8000) >> 15;
var10 += (var14 * var8 >> 16) + var9;
}
for (var14 = 0; var14 < 5; ++var14) {
if (this._y[var14] != 0) {
var15 = i + _q[var14];
if (var15 < len) {
buf[var15] += this.sample(this.osc0_.waveform, _c[var14], var13 * _p[var14] >> 15);
_c[var14] += (var12 * _t[var14] >> 16) + _w[var14];
}
}
}
}
if (this.osc6_ != null) {
this.osc6_.reset();
this.osc7_.reset();
int var11 = 0;
boolean var19 = true;
for (int i = 0; i < len; ++i) {
final int var15 = this.osc6_.next(len);
final int var16 = this.osc7_.next(len);
final int var12;
if (var19) {
var12 = this.osc6_._d + ((this.osc6_._i - this.osc6_._d) * var15 >> 8);
} else {
var12 = this.osc6_._d + ((this.osc6_._i - this.osc6_._d) * var16 >> 8);
}
var11 += 256;
if (var11 >= var12) {
var11 = 0;
var19 = !var19;
}
if (var19) {
buf[i] = 0;
}
}
}
if (this._f > 0 && this._b > 0) {
final int var11 = (int) ((double) this._f * samplesPerMs);
for (int i = var11; i < len; ++i) {
buf[i] += buf[i - var11] * this._b / 100;
}
}
if (this._k._d[0] > 0 || this._k._d[1] > 0) {
this.osc8_.reset();
int var11 = this.osc8_.next(len + 1);
int var12 = this._k.a197(0, (float) var11 / 65536.0F);
int var13 = this._k.a197(1, (float) var11 / 65536.0F);
if (len >= var12 + var13) {
int var14 = 0;
final int var15 = Math.min(var13, len - var12);
while (var14 < var15) {
int var16 = (int) ((long) buf[var14 + var12] * (long) fh_._g >> 16);
for (int var17 = 0; var17 < var12; ++var17) {
var16 += (int) ((long) buf[var14 + var12 - 1 - var17] * (long) fh_._e[0][var17] >> 16);
}
for (int var17 = 0; var17 < var14; ++var17) {
var16 -= (int) ((long) buf[var14 - 1 - var17] * (long) fh_._e[1][var17] >> 16);
}
buf[var14] = var16;
var11 = this.osc8_.next(len + 1);
++var14;
}
int var15a = 128;
while (true) {
if (var15a > len - var12) {
var15a = len - var12;
}
while (var14 < var15a) {
int var16 = (int) ((long) buf[var14 + var12] * (long) fh_._g >> 16);
for (int var17 = 0; var17 < var12; ++var17) {
var16 += (int) ((long) buf[var14 + var12 - 1 - var17] * (long) fh_._e[0][var17] >> 16);
}
for (int var17 = 0; var17 < var13; ++var17) {
var16 -= (int) ((long) buf[var14 - 1 - var17] * (long) fh_._e[1][var17] >> 16);
}
buf[var14] = var16;
var11 = this.osc8_.next(len + 1);
++var14;
}
if (var14 >= len - var12) {
while (var14 < len) {
int var16 = 0;
for (int var17 = var14 + var12 - len; var17 < var12; ++var17) {
var16 += (int) ((long) buf[var14 + var12 - 1 - var17] * (long) fh_._e[0][var17] >> 16);
}
for (int var17 = 0; var17 < var13; ++var17) {
var16 -= (int) ((long) buf[var14 - 1 - var17] * (long) fh_._e[1][var17] >> 16);
}
buf[var14] = var16;
this.osc8_.next(len + 1);
++var14;
}
break;
}
var12 = this._k.a197(0, (float) var11 / 65536.0F);
var13 = this._k.a197(1, (float) var11 / 65536.0F);
var15a += 128;
}
}
}
for (int i = 0; i < len; ++i) {
if (buf[i] < -32768) {
buf[i] = -32768;
}
if (buf[i] > 32767) {
buf[i] = 32767;
}
}
return buf;
}
public void initialize(final Buffer buf) {
this.osc0_ = new OscillatorState();
this.osc0_.initialize(buf);
this.osc1_ = new OscillatorState();
this.osc1_.initialize(buf);
final int peek1 = buf.readUByte();
if (peek1 != 0) {
--buf.pos;
this.osc2_ = new OscillatorState();
this.osc2_.initialize(buf);
this.osc3_ = new OscillatorState();
this.osc3_.initialize(buf);
}
final int peek2 = buf.readUByte();
if (peek2 != 0) {
--buf.pos;
this.osc4_ = new OscillatorState();
this.osc4_.initialize(buf);
this.osc5_ = new OscillatorState();
this.osc5_.initialize(buf);
}
final int peek3 = buf.readUByte();
if (peek3 != 0) {
--buf.pos;
this.osc6_ = new OscillatorState();
this.osc6_.initialize(buf);
this.osc7_ = new OscillatorState();
this.osc7_.initialize(buf);
}
for (int i = 0; i < 10; ++i) {
final int peek4 = buf.readVariable8_16();
if (peek4 == 0) {
break;
}
this._y[i] = peek4;
this._x[i] = buf.readBiasedVariable8_16();
this._h[i] = buf.readVariable8_16();
}
this._f = buf.readVariable8_16();
this._b = buf.readVariable8_16();
this.durMs = buf.readUShort();
this.delayMs = buf.readUShort();
this._k = new fh_();
this.osc8_ = new OscillatorState();
this._k.a086(buf, this.osc8_);
}
private int sample(final int type, final int phase, final int amplitude) {
if (type == Waveform.SQUARE) {
return ((phase & 0x7fff) < 0x4000) ? amplitude : -amplitude;
} else if (type == Waveform.SINE) {
return (SINE[phase & 0x7fff] * amplitude) >> 14;
} else if (type == Waveform.SAWTOOTH) {
return (((phase & 0x7fff) * amplitude) >> 14) - amplitude;
} else if (type == Waveform.NOISE) {
return NOISE[(phase / 2607) & 0x7fff] * amplitude;
} else {
return 0;
}
}
@SuppressWarnings("WeakerAccess")
private static final class Waveform {
public static final int SQUARE = 1;
public static final int SINE = 2;
public static final int SAWTOOTH = 3;
public static final int NOISE = 4;
}
}

View File

@ -1,65 +0,0 @@
package funorb.audio;
import funorb.io.Buffer;
public final class OscillatorState {
public int _d;
public int _i;
public int waveform;
private int count = 2;
private int[] values1 = new int[2];
private int[] values2 = new int[2];
private int _g;
private int _e;
private int _b;
private int _j;
private int pos;
public OscillatorState() {
this.values1[1] = 65535;
this.values2[1] = 65535;
}
public void initialize(final Buffer buffer) {
this.waveform = buffer.readUByte();
this._d = buffer.readInt();
this._i = buffer.readInt();
this.read(buffer);
}
public void read(final Buffer buffer) {
this.count = buffer.readUByte();
this.values1 = new int[this.count];
this.values2 = new int[this.count];
for (int i = 0; i < this.count; ++i) {
this.values1[i] = buffer.readUShort();
this.values2[i] = buffer.readUShort();
}
}
public void reset() {
this._e = 0;
this.pos = 0;
this._b = 0;
this._j = 0;
this._g = 0;
}
public int next(final int len) {
if (this._g >= this._e) {
this._j = this.values2[this.pos++] << 15;
if (this.pos >= this.count) {
this.pos = this.count - 1;
}
this._e = (int) (((double) this.values1[this.pos] / 65536.0D) * (double) len);
if (this._e > this._g) {
this._b = ((this.values2[this.pos] << 15) - this._j) / (this._e - this._g);
}
}
this._j += this._b;
++this._g;
return this._j - this._b >> 15;
}
}

View File

@ -0,0 +1,324 @@
package funorb.audio;
import funorb.io.Buffer;
import java.util.Arrays;
import java.util.Random;
public final class Synth {
private static final double _120TH_ROOT_OF_2 = 1.0057929410678534D;
private static final int[] NOISE = new int[0x8000];
private static final int[] SINE = new int[0x8000];
private static final int[] buf;
private static final int[] harmVolScaled_idk;
private static final int[] harmDelScaled_idk;
private static final int[] harmFreq_idk;
private static final int[] harmPhase_idk;
private static final int[] harmFreqMin_idk;
static {
final Random var0 = new Random(0L);
for (int i = 0; i < 0x8000; ++i) {
NOISE[i] = (var0.nextInt() & 2) - 1;
}
for (int i = 0; i < 0x8000; ++i) {
SINE[i] = (int) (Math.sin((double) i * Math.PI / 0x4000) * 0x4000);
}
buf = new int[220500];
harmDelScaled_idk = new int[5];
harmFreq_idk = new int[5];
harmVolScaled_idk = new int[5];
harmFreqMin_idk = new int[5];
harmPhase_idk = new int[5];
}
private final int[] harmVol_idk = new int[]{0, 0, 0, 0, 0};
private final int[] harmSemis_idk = new int[]{0, 0, 0, 0, 0};
private final int[] harmDel_idk = new int[]{0, 0, 0, 0, 0};
public int posMs = 0;
public int lengthMs = 500;
private SynthMystery _k;
private int echoTime = 0;
private SynthEnvelope envGapOn;
private SynthEnvelope envBaseFreq;
private SynthEnvelope envBaseAmp;
private SynthEnvelope envFmRate;
private SynthEnvelope envFmRange;
private SynthEnvelope envAmRate;
private SynthEnvelope envAmRange;
private int echoAmount = 100;
private SynthEnvelope osc8_;
private SynthEnvelope envGapOff;
public int[] generateS16(final int len, final int lenMs) {
Arrays.fill(buf, 0, len, 0);
if (lenMs < 10) {
return buf;
}
final double samplesPerMs = (double) len / ((double) lenMs + 0.0D);
this.envBaseFreq.reset();
this.envBaseAmp.reset();
int osc2RangeScaled = 0;
int osc2MinScaled = 0;
int oscFmPhase = 0;
if (this.envFmRate != null) {
this.envFmRate.reset();
this.envFmRange.reset();
osc2RangeScaled = (int) ((double) (this.envFmRate.max - this.envFmRate.min) * 32.768D / samplesPerMs);
osc2MinScaled = (int) ((double) this.envFmRate.min * 32.768D / samplesPerMs);
}
int osc4RangeScaled = 0;
int osc4MinScaled = 0;
int oscAmpPhase = 0;
if (this.envAmRate != null) {
this.envAmRate.reset();
this.envAmRange.reset();
osc4RangeScaled = (int) ((double) (this.envAmRate.max - this.envAmRate.min) * 32.768D / samplesPerMs);
osc4MinScaled = (int) ((double) this.envAmRate.min * 32.768D / samplesPerMs);
}
for (int harm_idk = 0; harm_idk < 5; ++harm_idk) {
if (this.harmVol_idk[harm_idk] != 0) {
harmPhase_idk[harm_idk] = 0;
harmDelScaled_idk[harm_idk] = (int) ((double) this.harmDel_idk[harm_idk] * samplesPerMs);
harmVolScaled_idk[harm_idk] = (this.harmVol_idk[harm_idk] << 14) / 100;
harmFreq_idk[harm_idk] = (int) ((double) (this.envBaseFreq.max - this.envBaseFreq.min) * 32.768D *
Math.pow(_120TH_ROOT_OF_2, this.harmSemis_idk[harm_idk]) / samplesPerMs);
harmFreqMin_idk[harm_idk] = (int) ((double) this.envBaseFreq.min * 32.768D / samplesPerMs);
}
}
for (int i = 0; i < len; ++i) {
int baseFreq = this.envBaseFreq.next(len);
int baseAmp = this.envBaseAmp.next(len);
int rate;
int range;
if (this.envFmRate != null) {
rate = this.envFmRate.next(len);
range = this.envFmRange.next(len);
baseFreq += this.sample(this.envFmRate.waveform, oscFmPhase, range) >> 1;
oscFmPhase += (rate * osc2RangeScaled >> 16) + osc2MinScaled;
}
if (this.envAmRate != null) {
rate = this.envAmRate.next(len);
range = this.envAmRange.next(len);
baseAmp = baseAmp * ((this.sample(this.envAmRate.waveform, oscAmpPhase, range) >> 1) + 0x8000) >> 15;
oscAmpPhase += (rate * osc4RangeScaled >> 16) + osc4MinScaled;
}
for (int harm_idk = 0; harm_idk < 5; ++harm_idk) {
if (this.harmVol_idk[harm_idk] != 0) {
int index = harm_idk + harmDelScaled_idk[harm_idk];
if (index < len) {
buf[index] += this.sample(
this.envBaseFreq.waveform,
harmPhase_idk[harm_idk],
baseAmp * harmVolScaled_idk[harm_idk] >> 15
);
harmPhase_idk[harm_idk] += (baseFreq * harmFreq_idk[harm_idk] >> 16) + harmFreqMin_idk[harm_idk];
}
}
}
}
if (this.envGapOff != null) {
this.envGapOff.reset();
this.envGapOn.reset();
int gapAccum = 0;
boolean gapOn = true;
for (int i = 0; i < len; ++i) {
final int gapOffThresh = this.envGapOff.next(len);
final int gapOnThresh = this.envGapOn.next(len);
final int gapThresh;
if (gapOn) {
gapThresh = this.envGapOff.min + ((this.envGapOff.max - this.envGapOff.min) * gapOffThresh >> 8);
} else {
gapThresh = this.envGapOff.min + ((this.envGapOff.max - this.envGapOff.min) * gapOnThresh >> 8);
}
gapAccum += 256;
if (gapAccum >= gapThresh) {
gapAccum = 0;
gapOn = !gapOn;
}
if (gapOn) {
buf[i] = 0;
}
}
}
if (this.echoTime > 0 && this.echoAmount > 0) {
final int delay = (int) ((double) this.echoTime * samplesPerMs);
for (int i = delay; i < len; ++i) {
buf[i] += buf[i - delay] * this.echoAmount / 100;
}
}
if (this._k._d[0] > 0 || this._k._d[1] > 0) {
this.osc8_.reset();
int var11 = this.osc8_.next(len + 1);
int var12 = this._k.a197(0, (float) var11 / 65536.0F);
int var13 = this._k.a197(1, (float) var11 / 65536.0F);
if (len >= var12 + var13) {
int var14 = 0;
final int var15 = Math.min(var13, len - var12);
while (var14 < var15) {
int var16 = (int) ((long) buf[var14 + var12] * (long) SynthMystery._g >> 16);
for (int var17 = 0; var17 < var12; ++var17) {
var16 += (int) ((long) buf[var14 + var12 - 1 - var17] * (long) SynthMystery._e[0][var17] >> 16);
}
for (int var17 = 0; var17 < var14; ++var17) {
var16 -= (int) ((long) buf[var14 - 1 - var17] * (long) SynthMystery._e[1][var17] >> 16);
}
buf[var14] = var16;
var11 = this.osc8_.next(len + 1);
++var14;
}
int var15a = 128;
while (true) {
if (var15a > len - var12) {
var15a = len - var12;
}
while (var14 < var15a) {
int var16 = (int) ((long) buf[var14 + var12] * (long) SynthMystery._g >> 16);
for (int var17 = 0; var17 < var12; ++var17) {
var16 += (int) ((long) buf[var14 + var12 - 1 - var17] * (long) SynthMystery._e[0][var17] >> 16);
}
for (int var17 = 0; var17 < var13; ++var17) {
var16 -= (int) ((long) buf[var14 - 1 - var17] * (long) SynthMystery._e[1][var17] >> 16);
}
buf[var14] = var16;
var11 = this.osc8_.next(len + 1);
++var14;
}
if (var14 >= len - var12) {
while (var14 < len) {
int var16 = 0;
for (int var17 = var14 + var12 - len; var17 < var12; ++var17) {
var16 += (int) ((long) buf[var14 + var12 - 1 - var17] * (long) SynthMystery._e[0][var17] >> 16);
}
for (int var17 = 0; var17 < var13; ++var17) {
var16 -= (int) ((long) buf[var14 - 1 - var17] * (long) SynthMystery._e[1][var17] >> 16);
}
buf[var14] = var16;
this.osc8_.next(len + 1);
++var14;
}
break;
}
var12 = this._k.a197(0, (float) var11 / 65536.0F);
var13 = this._k.a197(1, (float) var11 / 65536.0F);
var15a += 128;
}
}
}
for (int i = 0; i < len; ++i) {
if (buf[i] < -32768) {
buf[i] = -32768;
}
if (buf[i] > 32767) {
buf[i] = 32767;
}
}
return buf;
}
public void initialize(final Buffer buf) {
this.envBaseFreq = new SynthEnvelope();
this.envBaseFreq.load(buf);
this.envBaseAmp = new SynthEnvelope();
this.envBaseAmp.load(buf);
final int peek1 = buf.readUByte();
if (peek1 != 0) {
--buf.pos;
this.envFmRate = new SynthEnvelope();
this.envFmRate.load(buf);
this.envFmRange = new SynthEnvelope();
this.envFmRange.load(buf);
}
final int peek2 = buf.readUByte();
if (peek2 != 0) {
--buf.pos;
this.envAmRate = new SynthEnvelope();
this.envAmRate.load(buf);
this.envAmRange = new SynthEnvelope();
this.envAmRange.load(buf);
}
final int peek3 = buf.readUByte();
if (peek3 != 0) {
--buf.pos;
this.envGapOff = new SynthEnvelope();
this.envGapOff.load(buf);
this.envGapOn = new SynthEnvelope();
this.envGapOn.load(buf);
}
for (int i = 0; i < 10; ++i) {
final int peek4 = buf.readVariable8_16();
if (peek4 == 0) {
break;
}
this.harmVol_idk[i] = peek4;
this.harmSemis_idk[i] = buf.readBiasedVariable8_16();
this.harmDel_idk[i] = buf.readVariable8_16();
}
this.echoTime = buf.readVariable8_16();
this.echoAmount = buf.readVariable8_16();
this.lengthMs = buf.readUShort();
this.posMs = buf.readUShort();
this._k = new SynthMystery();
this.osc8_ = new SynthEnvelope();
this._k.load(buf, this.osc8_);
}
private int sample(final int type, final int phase, final int amplitude) {
if (type == Waveform.SQUARE) {
return ((phase & 0x7fff) < 0x4000) ? amplitude : -amplitude;
} else if (type == Waveform.SINE) {
return (SINE[phase & 0x7fff] * amplitude) >> 14;
} else if (type == Waveform.SAWTOOTH) {
return (((phase & 0x7fff) * amplitude) >> 14) - amplitude;
} else if (type == Waveform.NOISE) {
return NOISE[(phase / 2607) & 0x7fff] * amplitude;
} else {
return 0;
}
}
@SuppressWarnings("WeakerAccess")
private static final class Waveform {
public static final int SQUARE = 1;
public static final int SINE = 2;
public static final int SAWTOOTH = 3;
public static final int NOISE = 4;
}
}

View File

@ -0,0 +1,66 @@
package funorb.audio;
import funorb.io.Buffer;
public final class SynthEnvelope {
public int min;
public int max;
public int waveform;
private int numSegs;
private int[] envPtsX;
private int[] envPtsY;
private int curSamples;
private int envSegEnd;
private int curSlope;
private int curY;
private int curSegIdx;
public SynthEnvelope() {
this.numSegs = 2;
this.envPtsX = new int[]{0, 65535};
this.envPtsY = new int[]{0, 65535};
}
public void load(final Buffer buffer) {
this.waveform = buffer.readUByte();
this.min = buffer.readInt();
this.max = buffer.readInt();
this.loadPoints(buffer);
}
public void loadPoints(final Buffer buffer) {
this.numSegs = buffer.readUByte();
this.envPtsX = new int[this.numSegs];
this.envPtsY = new int[this.numSegs];
for (int i = 0; i < this.numSegs; ++i) {
this.envPtsX[i] = buffer.readUShort();
this.envPtsY[i] = buffer.readUShort();
}
}
public void reset() {
this.envSegEnd = 0;
this.curSegIdx = 0;
this.curSlope = 0;
this.curY = 0;
this.curSamples = 0;
}
public int next(final int len) {
if (this.curSamples >= this.envSegEnd) {
this.curY = this.envPtsY[this.curSegIdx++] << 15;
if (this.curSegIdx >= this.numSegs) {
this.curSegIdx = this.numSegs - 1;
}
this.envSegEnd = (int) (((double) this.envPtsX[this.curSegIdx] / 65536.0D) * (double) len);
if (this.envSegEnd > this.curSamples) {
this.curSlope = ((this.envPtsY[this.curSegIdx] << 15) - this.curY) / (this.envSegEnd - this.curSamples);
}
}
this.curY += this.curSlope;
++this.curSamples;
return this.curY - this.curSlope >> 15;
}
}

View File

@ -2,7 +2,7 @@ package funorb.audio;
import funorb.io.Buffer;
public final class fh_ {
public final class SynthMystery {
public static final int[][] _e = new int[2][8];
private static final float[][] _f = new float[2][8];
public static int _g;
@ -17,42 +17,45 @@ public final class fh_ {
return var1 * 3.1415927F / 11025.0F;
}
public void a086(final Buffer var1, final OscillatorState var2) {
final int var3 = var1.readUByte();
public void load(final Buffer buf, final SynthEnvelope env) {
final int var3 = buf.readUByte();
this._d[0] = var3 >> 4;
this._d[1] = var3 & 15;
if (var3 == 0) {
this._b[1] = 0;
this._b[0] = 0;
} else {
this._b[0] = var1.readUShort();
this._b[1] = var1.readUShort();
final int var4 = var1.readUByte();
return;
}
int var5;
int var6;
for (var5 = 0; var5 < 2; ++var5) {
for (var6 = 0; var6 < this._d[var5]; ++var6) {
this._a[var5][0][var6] = var1.readUShort();
this._c[var5][0][var6] = var1.readUShort();
this._b[0] = buf.readUShort();
this._b[1] = buf.readUShort();
final int var4 = buf.readUByte();
int var5;
int var6;
for (var5 = 0; var5 < 2; ++var5) {
for (var6 = 0; var6 < this._d[var5]; ++var6) {
this._a[var5][0][var6] = buf.readUShort();
this._c[var5][0][var6] = buf.readUShort();
}
}
for (var5 = 0; var5 < 2; ++var5) {
for (var6 = 0; var6 < this._d[var5]; ++var6) {
if ((var4 & 1 << var5 * 4 << var6) == 0) {
this._a[var5][1][var6] = this._a[var5][0][var6];
this._c[var5][1][var6] = this._c[var5][0][var6];
} else {
this._a[var5][1][var6] = buf.readUShort();
this._c[var5][1][var6] = buf.readUShort();
}
}
}
for (var5 = 0; var5 < 2; ++var5) {
for (var6 = 0; var6 < this._d[var5]; ++var6) {
if ((var4 & 1 << var5 * 4 << var6) == 0) {
this._a[var5][1][var6] = this._a[var5][0][var6];
this._c[var5][1][var6] = this._c[var5][0][var6];
} else {
this._a[var5][1][var6] = var1.readUShort();
this._c[var5][1][var6] = var1.readUShort();
}
}
}
if (var4 != 0 || this._b[1] != this._b[0]) {
var2.read(var1);
}
if (var4 != 0 || this._b[1] != this._b[0]) {
env.loadPoints(buf);
}
}