mirror of
https://github.com/lexi-lambda/shattered-plans.git
synced 2024-11-22 11:12:29 +03:00
Almost fully figured out the synth format decoder
This commit is contained in:
parent
13a7b96fab
commit
5840b1fa80
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
324
src/main/java/funorb/audio/Synth.java
Normal file
324
src/main/java/funorb/audio/Synth.java
Normal 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;
|
||||
}
|
||||
}
|
66
src/main/java/funorb/audio/SynthEnvelope.java
Normal file
66
src/main/java/funorb/audio/SynthEnvelope.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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,24 +17,28 @@ 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;
|
||||
}
|
||||
|
||||
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] = var1.readUShort();
|
||||
this._c[var5][0][var6] = var1.readUShort();
|
||||
this._a[var5][0][var6] = buf.readUShort();
|
||||
this._c[var5][0][var6] = buf.readUShort();
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,15 +48,14 @@ public final class fh_ {
|
||||
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();
|
||||
this._a[var5][1][var6] = buf.readUShort();
|
||||
this._c[var5][1][var6] = buf.readUShort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (var4 != 0 || this._b[1] != this._b[0]) {
|
||||
var2.read(var1);
|
||||
}
|
||||
env.loadPoints(buf);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user