channel.ch$fbOutputHandle = port.op$Joint1Box;
channel.ch$bfOutputHandle = port.op$Joint2Box;
channel.ch$c2InputHandle = port.op$Joint4Box;
channel.ch$c1OutputHandle = channel.ch$m2OutputHandle = channel.ch$OutputBox;
break;
case 7:
channel.ch$bfOutputHandle = port.op$Joint2Box;
channel.ch$c2InputHandle = port.op$Joint4Box;
channel.ch$fbOutputHandle = channel.ch$c1OutputHandle = channel.ch$m2OutputHandle = channel.ch$OutputBox;
break;
}
v >>= 3;
channel.ch$fbScale = v == 0 ? 0 : 1 << (v + 6);
}
function chSetPAN (channel, v) {
v &= 3;
channel.ch$PAN = v;
channel.ch$LeftMask = -(v & 1);
channel.ch$RightMask = -(v >> 1);
}
function chSetKC (channel, v) {
v &= 127;
if (channel.ch$KC != v) {
channel.ch$KC = v;
channel.ch$KeyIndex = 768 + ((v - (v >> 2)) << 6) + channel.ch$KF;
slRefreshEG (channel.ch$M1);
slRefreshEG (channel.ch$M2);
slRefreshEG (channel.ch$C1);
slRefreshEG (channel.ch$C2);
}
}
function chSetKF (channel, v) {
v &= 63;
if (channel.ch$KF != v) {
channel.ch$KF = v;
channel.ch$KeyIndex = v |= channel.ch$KeyIndex & ~63;
channel.ch$M1.sl$Freq = ((opmFreqTable[v + channel.ch$M1.sl$Detune2Depth] + channel.ch$M1.sl$Detune1Freq) * channel.ch$M1.sl$Multiply) >>> 1;
channel.ch$M2.sl$Freq = ((opmFreqTable[v + channel.ch$M2.sl$Detune2Depth] + channel.ch$M2.sl$Detune1Freq) * channel.ch$M2.sl$Multiply) >>> 1;
channel.ch$C1.sl$Freq = ((opmFreqTable[v + channel.ch$C1.sl$Detune2Depth] + channel.ch$C1.sl$Detune1Freq) * channel.ch$C1.sl$Multiply) >>> 1;
channel.ch$C2.sl$Freq = ((opmFreqTable[v + channel.ch$C2.sl$Detune2Depth] + channel.ch$C2.sl$Detune1Freq) * channel.ch$C2.sl$Multiply) >>> 1;
}
}
function chSetAMS (channel, v) {
v &= 3;
channel.ch$AMS = v;
channel.ch$ShiftAMS = v == 0 ? 0 : 1 << (v - 1);
}
function chSetPMS (channel, v) {
v &= 7;
channel.ch$PMS = v;
channel.ch$ShiftPMS = v == 0 ? 0 : v < 6 ? 64 >> (6 - v) : 64 << (v - 5);
}
function slKeyOn (slot, mask) {
let port = slot.sl$Port;
if (slot.sl$KeyStatus == 0) {
slot.sl$Phase = 0;
slot.sl$Stage = OPMStage_ATTACK;
slot.sl$TransitionMask = (4 << slot.sl$AttackShift) - 4;
slot.sl$Volume += (~slot.sl$Volume * (slot.sl$Attack3 | (slot.sl$Attack4 << (port.op$EGCounter >> slot.sl$AttackShift & 28)) >>> 28)) >> 4;
if (slot.sl$Volume <= 0) {
slot.sl$Volume = 0;
slot.sl$Stage = OPMStage_DECAY;
slot.sl$TransitionMask = (4 << slot.sl$DecayShift) - 4;
}
}
slot.sl$KeyStatus |= mask;
}
function slKeyOff (slot, mask) {
if (slot.sl$KeyStatus != 0) {
slot.sl$KeyStatus &= mask;
if (slot.sl$KeyStatus == 0 &&
slot.sl$Stage < OPMStage_RELEASE) {
slot.sl$Stage = OPMStage_RELEASE;
slot.sl$TransitionMask = (4 << slot.sl$ReleaseShift) - 4;
}
}
}
function slRefreshEG (slot) {
slot.sl$Detune1Freq = opmDT1FreqTable[slot.sl$Detune1Page + (slot.sl$Channel.ch$KC >> 2)];
slot.sl$Freq = ((opmFreqTable[slot.sl$Channel.ch$KeyIndex + slot.sl$Detune2Depth] + slot.sl$Detune1Freq) * slot.sl$Multiply) >>> 1;
let u = slot.sl$Channel.ch$KC >> slot.sl$KeyScale;
let v = slot.sl$AttackRate + u;
if (v < 94) {
slot.sl$AttackShift = OPM_EG_SHIFT_TABLE[v];
if (slot.sl$Stage == OPMStage_ATTACK) {
slot.sl$TransitionMask = (4 << slot.sl$AttackShift) - 4;
}
slot.sl$Attack3 = 0;
slot.sl$Attack4 = OPM_EG_TABLE_X[v];
} else {
slot.sl$AttackShift = 0;
if (slot.sl$Stage == OPMStage_ATTACK) {
slot.sl$TransitionMask = 0;
}
slot.sl$Attack3 = 16;
slot.sl$Attack4 = 0;
}
v = slot.sl$DecayRate + u;
slot.sl$DecayShift = OPM_EG_SHIFT_TABLE[v];
if (slot.sl$Stage == OPMStage_DECAY) {
slot.sl$TransitionMask = (4 << slot.sl$DecayShift) - 4;
}
slot.sl$Decay3 = 0;
slot.sl$Decay4 = OPM_EG_TABLE_X[v];
v = slot.sl$SustainRate + u;
slot.sl$SustainShift = OPM_EG_SHIFT_TABLE[v];
if (slot.sl$Stage == OPMStage_SUSTAIN) {
slot.sl$TransitionMask = (4 << slot.sl$SustainShift) - 4;
}
slot.sl$Sustain3 = 0;
slot.sl$Sustain4 = OPM_EG_TABLE_X[v];
v = slot.sl$ReleaseRate + u;
slot.sl$ReleaseShift = OPM_EG_SHIFT_TABLE[v];
if (slot.sl$Stage == OPMStage_RELEASE) {
slot.sl$TransitionMask = (4 << slot.sl$ReleaseShift) - 4;
}
slot.sl$Release3 = 0;
slot.sl$Release4 = OPM_EG_TABLE_X[v];
}
function slSetMUL (slot, v) {
let t = (v & 15) << 1;
if (t == 0) {
t = 1;
}
if (slot.sl$Multiply != t) {
slot.sl$Multiply = t;
slot.sl$Freq = ((opmFreqTable[slot.sl$Channel.ch$KeyIndex + slot.sl$Detune2Depth] + slot.sl$Detune1Freq) * t) >>> 1;
}
}
function slSetDT1 (slot, v) {
v = (v & 7) << 5;
if (slot.sl$Detune1Page != v) {
slot.sl$Detune1Page = v;
slot.sl$Detune1Freq = opmDT1FreqTable[slot.sl$Detune1Page + (slot.sl$Channel.ch$KC >> 2)];
slot.sl$Freq = ((opmFreqTable[slot.sl$Channel.ch$KeyIndex + slot.sl$Detune2Depth] + slot.sl$Detune1Freq) * slot.sl$Multiply) >>> 1;
}
}
function slSetTL (slot, v) {
slot.sl$TotalLevel = (v & 127) << (OPM_TL_BITS - 7);
}
function slSetAR (slot, v) {
v &= 31;
v = ((v + 31) & 32) + (v << 1);
if (slot.sl$AttackRate != v) {
slot.sl$AttackRate = v;
v += slot.sl$Channel.ch$KC >> slot.sl$KeyScale;
if (v < 94) {
slot.sl$AttackShift = OPM_EG_SHIFT_TABLE[v];
if (slot.sl$Stage == OPMStage_ATTACK) {
slot.sl$TransitionMask = (4 << slot.sl$AttackShift) - 4;
}
slot.sl$Attack3 = 0;
slot.sl$Attack4 = OPM_EG_TABLE_X[v];
} else {
slot.sl$AttackShift = 0;
if (slot.sl$Stage == OPMStage_ATTACK) {
slot.sl$TransitionMask = 0;
}
slot.sl$Attack3 = 16;
slot.sl$Attack4 = 0;
}
}
}
function slSetKS (slot, v) {
v &= 3;
v = 5 - v;
if (slot.sl$KeyScale != v) {
slot.sl$KeyScale = v;
let u = slot.sl$Channel.ch$KC >> v;
v = slot.sl$AttackRate + u;
if (v < 94) {
slot.sl$AttackShift = OPM_EG_SHIFT_TABLE[v];
if (slot.sl$Stage == OPMStage_ATTACK) {
slot.sl$TransitionMask = (4 << slot.sl$AttackShift) - 4;
}
slot.sl$Attack3 = 0;
slot.sl$Attack4 = OPM_EG_TABLE_X[v];
} else {
slot.sl$AttackShift = 0;
if (slot.sl$Stage == OPMStage_ATTACK) {
slot.sl$TransitionMask = 0;
}
slot.sl$Attack3 = 16;
slot.sl$Attack4 = 0;
}
v = slot.sl$DecayRate + u;
slot.sl$DecayShift = OPM_EG_SHIFT_TABLE[v];
if (slot.sl$Stage == OPMStage_DECAY) {
slot.sl$TransitionMask = (4 << slot.sl$DecayShift) - 4;
}
slot.sl$Decay3 = 0;
slot.sl$Decay4 = OPM_EG_TABLE_X[v];
v = slot.sl$SustainRate + u;
slot.sl$SustainShift = OPM_EG_SHIFT_TABLE[v];
if (slot.sl$Stage == OPMStage_SUSTAIN) {
slot.sl$TransitionMask = (4 << slot.sl$SustainShift) - 4;
}
slot.sl$Sustain3 = 0;
slot.sl$Sustain4 = OPM_EG_TABLE_X[v];
v = slot.sl$ReleaseRate + u;
slot.sl$ReleaseShift = OPM_EG_SHIFT_TABLE[v];
if (slot.sl$Stage == OPMStage_RELEASE) {
slot.sl$TransitionMask = (4 << slot.sl$ReleaseShift) - 4;
}
slot.sl$Release3 = 0;
slot.sl$Release4 = OPM_EG_TABLE_X[v];
}
}
function slSetD1R (slot, v) {
v &= 31;
v = ((v + 31) & 32) + (v << 1);
if (slot.sl$DecayRate != v) {
slot.sl$DecayRate = v;
v += slot.sl$Channel.ch$KC >> slot.sl$KeyScale;
slot.sl$DecayShift = OPM_EG_SHIFT_TABLE[v];
if (slot.sl$Stage == OPMStage_DECAY) {
slot.sl$TransitionMask = (4 << slot.sl$DecayShift) - 4;
}
slot.sl$Decay3 = 0;
slot.sl$Decay4 = OPM_EG_TABLE_X[v];
}
}
function slSetAMSEN (slot, v) {
v &= 1;
slot.sl$AMSMask = -v;
}
function slSetD2R (slot, v) {
v &= 31;
v = ((v + 31) & 32) + (v << 1);
if (slot.sl$SustainRate != v) {
slot.sl$SustainRate = v;
v += slot.sl$Channel.ch$KC >> slot.sl$KeyScale;
slot.sl$SustainShift = OPM_EG_SHIFT_TABLE[v];
if (slot.sl$Stage == OPMStage_SUSTAIN) {
slot.sl$TransitionMask = (4 << slot.sl$SustainShift) - 4;
}
slot.sl$Sustain3 = 0;
slot.sl$Sustain4 = OPM_EG_TABLE_X[v];
}
}
function slSetDT2 (slot, v) {
v &= 3;
v = ((384 << 20 | 500 << 10 | 608) >>> (30 - v * 10)) & 1023;
if (slot.sl$Detune2Depth != v) {
slot.sl$Detune2Depth = v;
slot.sl$Freq = ((opmFreqTable[slot.sl$Channel.ch$KeyIndex + v] + slot.sl$Detune1Freq) * slot.sl$Multiply) >>> 1;
}
}
function slSetRR (slot, v) {
v &= 15;
v = 32 + 2 + (v << 2);
if (slot.sl$ReleaseRate != v) {
slot.sl$ReleaseRate = v;
v += slot.sl$Channel.ch$KC >> slot.sl$KeyScale;
slot.sl$ReleaseShift = OPM_EG_SHIFT_TABLE[v];
if (slot.sl$Stage == OPMStage_RELEASE) {
slot.sl$TransitionMask = (4 << slot.sl$ReleaseShift) - 4;
}
slot.sl$Release3 = 0;
slot.sl$Release4 = OPM_EG_TABLE_X[v];
}
}
function slSetD1L (slot, v) {
v &= 15;
slot.sl$DecayLevel = (((v + 1) & 16) + v) << (OPM_TL_BITS - 5);
v &= 15;
}
function opmAdvance (from, to) {
for (let pn = 0; pn < OPM_PORT_COUNT; pn++) {
let port = opmPortArray[pn];
for (let k = from; k < to; ) {
if (--port.op$EGTimer == 0) {
port.op$EGTimer = 3;
port.op$EGCounter += 4;
for (let i = 0; i < OPM_SLOT_COUNT; i++) {
let slot = port.op$Slot[i];
if ((port.op$EGCounter & slot.sl$TransitionMask) == 0) {
switch (slot.sl$Stage) {
case OPMStage_ATTACK:
slot.sl$Volume += (~slot.sl$Volume * (slot.sl$Attack3 | (slot.sl$Attack4 << (port.op$EGCounter >> slot.sl$AttackShift & 28)) >>> 28)) >> 4;
if (slot.sl$Volume <= 0) {
slot.sl$Volume = 0;
slot.sl$Stage = OPMStage_DECAY;
slot.sl$TransitionMask = (4 << slot.sl$DecayShift) - 4;
}
break;
case OPMStage_DECAY:
slot.sl$Volume += slot.sl$Decay3 | (slot.sl$Decay4 << (port.op$EGCounter >> slot.sl$DecayShift & 28)) >>> 28;
if (slot.sl$Volume >= slot.sl$DecayLevel) {
slot.sl$Stage = OPMStage_SUSTAIN;
slot.sl$TransitionMask = (4 << slot.sl$SustainShift) - 4;
}
break;
case OPMStage_SUSTAIN:
slot.sl$Volume += slot.sl$Sustain3 | (slot.sl$Sustain4 << (port.op$EGCounter >> slot.sl$SustainShift & 28)) >>> 28;
if (slot.sl$Volume >= OPM_TL_SIZE - 1) {
slot.sl$Volume = OPM_TL_SIZE - 1;
slot.sl$Stage = OPMStage_SILENCE;
slot.sl$TransitionMask = 1;
}
break;
case OPMStage_RELEASE:
slot.sl$Volume += slot.sl$Release3 | (slot.sl$Release4 << (port.op$EGCounter >> slot.sl$ReleaseShift & 28)) >>> 28;
if (slot.sl$Volume >= OPM_TL_SIZE - 1) {
slot.sl$Volume = OPM_TL_SIZE - 1;
slot.sl$Stage = OPMStage_SILENCE;
slot.sl$TransitionMask = 1;
}
break;
case OPMStage_SILENCE:
break;
}
}
}
}
for (let i = 0; i < OPM_CHANNEL_COUNT; i++) {
let channel = port.op$Channel[i];
port.op$Joint1Box[0] = port.op$Joint2Box[0] = port.op$Joint3Box[0] = port.op$Joint4Box[0] = channel.ch$OutputBox[0] = 0;
channel.ch$bfOutputHandle[0] = channel.ch$bfInputValue;
channel.ch$fbOutputHandle[0] = channel.ch$fbInputValue;
let amsValue = port.op$LFOAMOutput * channel.ch$ShiftAMS;
let env = channel.ch$M1.sl$TotalLevel + channel.ch$M1.sl$Volume + (amsValue & channel.ch$M1.sl$AMSMask);
let fbValue = (channel.ch$fbPreviousValue + channel.ch$fbInputValue) * channel.ch$fbScale;
channel.ch$fbPreviousValue = channel.ch$fbInputValue;
if (env < OPM_ENV_QUIET) {
let p = (env << 3) + opmSinTable[((channel.ch$M1.sl$Phase & ~OPM_PHASE_MASK) + fbValue) >> OPM_PHASE_SHIFT & OPM_SIN_MASK];
channel.ch$fbInputValue = p < OPM_TL_TABLE_SIZE ? opmTLTable[p] : 0;
} else {
channel.ch$fbInputValue = 0;
}
env = channel.ch$M2.sl$TotalLevel + channel.ch$M2.sl$Volume + (amsValue & channel.ch$M2.sl$AMSMask);
if (env < OPM_ENV_QUIET) {
let p = (env << 3) + opmSinTable[((channel.ch$M2.sl$Phase >> OPM_PHASE_SHIFT) + (channel.ch$m2InputHandle[0] >> (OPM_PHASE_SHIFT - 15))) & OPM_SIN_MASK];
if (p < OPM_TL_TABLE_SIZE) {
channel.ch$m2OutputHandle[0] += opmTLTable[p];
}
}
env = channel.ch$C1.sl$TotalLevel + channel.ch$C1.sl$Volume + (amsValue & channel.ch$C1.sl$AMSMask);
if (env < OPM_ENV_QUIET) {
let p = (env << 3) + opmSinTable[((channel.ch$C1.sl$Phase >> OPM_PHASE_SHIFT) + (channel.ch$c1InputHandle[0] >> (OPM_PHASE_SHIFT - 15))) & OPM_SIN_MASK];
if (p < OPM_TL_TABLE_SIZE) {
channel.ch$c1OutputHandle[0] += opmTLTable[p];
}
}
env = channel.ch$C2.sl$TotalLevel + channel.ch$C2.sl$Volume + (amsValue & channel.ch$C2.sl$AMSMask);
if (channel.ch$NoiseOn) {
channel.ch$OutputBox[0] += ((port.op$NoiseRegister >> 15 & 2) - 1) * (env < 0x3ff ? (env ^ 0x3ff) << 1 : 0);
} else {
if (env < OPM_ENV_QUIET) {
let p = (env << 3) + opmSinTable[((channel.ch$C2.sl$Phase >> OPM_PHASE_SHIFT) + (channel.ch$c2InputHandle[0] >> (OPM_PHASE_SHIFT - 15))) & OPM_SIN_MASK];
if (p < OPM_TL_TABLE_SIZE) {
channel.ch$OutputBox[0] += opmTLTable[p];
}
}
}
channel.ch$bfInputValue = channel.ch$bfInputHandle[0];
}
let l = 0;
let r = 0;
for (let i = 0; i < OPM_CHANNEL_COUNT; i++) {
let channel = port.op$Channel[i];
l += channel.ch$OutputBox[0] & channel.ch$LeftMask;
r += channel.ch$OutputBox[0] & channel.ch$RightMask;
}
internalBufferLeft[k] += l * (1 / 8192);
internalBufferRight[k] += r * (1 / 8192);
k++;
if (port.op$LFOActive && --port.op$LFOCounterMinor == 0) {
port.op$LFOCounterMinor = port.op$LFOPeriodMinor;
let t = port.op$LFOCounterMajor + port.op$LFOPeriodMajor;
port.op$LFOCounterMajor = t & 15;
port.op$LFOWaveIndex = (port.op$LFOWaveIndex + (t >>> 4)) & 255;
port.op$LFOAMValue = opmLFOAMTable[port.op$WAVE256 + port.op$LFOWaveIndex];
port.op$LFOPMValue = opmLFOPMTable[port.op$WAVE256 + port.op$LFOWaveIndex];
}
port.op$LFOAMOutput = (port.op$LFOAMValue * port.op$AMD) >>> 7;
let u = port.op$LFOPMValue * port.op$PMD;
port.op$LFOPMOutput = u >= 0 ? u >> 7 : -(-u >> 7);
port.op$NoisePhase += port.op$NoiseFrequency;
if (port.op$NoisePhase >>> 16 != 0) {
port.op$NoiseRegister = (((port.op$NoiseRegister ^ port.op$NoiseRegister >>> 3) & 1) ^ 1) << 16 | port.op$NoiseRegister >>> 1;
port.op$NoisePhase &= 65535;
}
for (let i = 0; i < OPM_CHANNEL_COUNT; i++) {
let channel = port.op$Channel[i];
let m1 = channel.ch$M1;
let m2 = channel.ch$M2;
let c1 = channel.ch$C1;
let c2 = channel.ch$C2;
let pmDepth = port.op$LFOPMOutput * channel.ch$ShiftPMS >> 6;
if (pmDepth != 0) {
let keyIndex = channel.ch$KeyIndex + pmDepth;
m1.sl$Phase += ((opmFreqTable[keyIndex + m1.sl$Detune2Depth] + m1.sl$Detune1Freq) * m1.sl$Multiply) >>> 1;
m2.sl$Phase += ((opmFreqTable[keyIndex + m2.sl$Detune2Depth] + m2.sl$Detune1Freq) * m2.sl$Multiply) >>> 1;
c1.sl$Phase += ((opmFreqTable[keyIndex + c1.sl$Detune2Depth] + c1.sl$Detune1Freq) * c1.sl$Multiply) >>> 1;
c2.sl$Phase += ((opmFreqTable[keyIndex + c2.sl$Detune2Depth] + c2.sl$Detune1Freq) * c2.sl$Multiply) >>> 1;
} else {
m1.sl$Phase += m1.sl$Freq;
m2.sl$Phase += m2.sl$Freq;
c1.sl$Phase += c1.sl$Freq;
c2.sl$Phase += c2.sl$Freq;
}
}
if (port.op$CSMRequest != 0) {
if (port.op$CSMRequest > 0) {
for (let i = 0; i < OPM_CHANNEL_COUNT; i++) {
let channel = port.op$Channel[i];
slKeyOn (channel.ch$M1, 2);
slKeyOn (channel.ch$M2, 2);
slKeyOn (channel.ch$C1, 2);
slKeyOn (channel.ch$C2, 2);
}
port.op$CSMRequest = -1;
} else {
for (let i = 0; i < OPM_CHANNEL_COUNT; i++) {
let channel = port.op$Channel[i];
slKeyOff (channel.ch$M1, ~2);
slKeyOff (channel.ch$M2, ~2);
slKeyOff (channel.ch$C1, ~2);
slKeyOff (channel.ch$C2, ~2);
}
port.op$CSMRequest = 0;
}
}
}
}
}
let pcmData = new Uint8Array (0);
let pcmRate = 4;
let pcmLeft = true;
let pcmRight = true;
const PCM_PORT_COUNT = 1;
let pcmPortArray;
let adpcmLowerTable;
let adpcmUpperTable;
let adpcmNextTable;
function pcmInit () {
let d4 = new Float32Array (16 * 49);
let p4 = new Int32Array (16 * 49);
for (let p = 0; p < 49; p++) {
let x = floor (16 * pow (1.1, p));
for (let n = 0; n < 16; n++) {
let i = p << 4 | n;
d4[i] = (1 - (n >> 2 & 2)) * ((n >> 2 & 1) * x + (n >> 1 & 1) * (x >> 1) + (n & 1) * (x >> 2) + (x >> 3)) * (1 / 2048);
p4[i] = max2 (0, min2 (48, p + ((n & 7) - 4 >> 3 | (n & 3) + 1 << 1)));
}
}
adpcmLowerTable = new Float32Array (256 * 49);
adpcmUpperTable = new Float32Array (256 * 49);
adpcmNextTable = new Int32Array (256 * 49);
for (let p = 0; p < 49; p++) {
for (let n = 0; n < 256; n++) {
let i = p << 8 | n;
let j = p << 4 | (n & 15);
adpcmLowerTable[i] = d4[j];
j = p4[j] << 4 | n >> 4;
adpcmUpperTable[i] = d4[j];
adpcmNextTable[i] = p4[j] << 8;
}
}
pcmPortArray = [];
for (let pn = 0; pn < PCM_PORT_COUNT; pn++) {
pcmPortArray[pn] = {
pp$RateNumber: 4,
pp$PanLeft: true,
pp$PanRight: true,
pp$Stage: 0,
pp$Buffer: new Uint8Array (0),
pp$Pointer: 0,
pp$Length: 0,
pp$Running: false,
pp$Data: 0,
pp$Data1: 0,
pp$Data2: 0,
pp$Data3: 0,
pp$TempBuffer: new Float32Array (32),
pp$TempPointer: 0,
pp$TempLength: 0
};
}
}
function pcmSet (data, rate, left, right) {
if (data !== undefined) {
pcmData = data;
}
if (rate !== undefined) {
pcmRate = rate;
}
if (left !== undefined) {
pcmLeft = left;
}
if (right !== undefined) {
pcmRight = right;
}
}
function pcmStart () {
let data = pcmData;
let rate = pcmRate;
let left = pcmLeft;
let right = pcmRight;
let idlePort = null;
let nearlyIdlePort = null;
for (let pn = 0; pn < PCM_PORT_COUNT; pn++) {
let port = pcmPortArray[pn];
if (!port.pp$Running) {
idlePort = port;
break;
}
if (nearlyIdlePort == null ||
port.pp$Length - port.pp$Pointer <
nearlyIdlePort.pp$Length - nearlyIdlePort.pp$Pointer) {
nearlyIdlePort = port;
}
}
if (idlePort == null) {
idlePort = nearlyIdlePort;
idlePort.pp$Running = false;
}
idlePort.pp$RateNumber = rate;
idlePort.pp$PanLeft = left;
idlePort.pp$PanRight = right;
idlePort.pp$Stage = 0;
idlePort.pp$Buffer = data;
idlePort.pp$Pointer = 0;
idlePort.pp$Length = data.length;
idlePort.pp$Running = true;
}
function pcmStop () {
for (let pn = 0; pn < PCM_PORT_COUNT; pn++) {
let port = pcmPortArray[pn];
port.pp$Running = false;
}
}
function pcmAdvance (from, to) {
for (let pn = 0; pn < PCM_PORT_COUNT; pn++) {
let port = pcmPortArray[pn];
if (!port.pp$Running) {
continue;
}
let rateNumber = port.pp$RateNumber;
let panLeft = port.pp$PanLeft;
let panRight = port.pp$PanRight;
let buffer = port.pp$Buffer;
let length = port.pp$Length;
let tempBuffer = port.pp$TempBuffer;
let pointer = port.pp$Pointer;
let data = port.pp$Data;
let data1 = port.pp$Data1;
let data2 = port.pp$Data2;
let data3 = port.pp$Data3;
let stage = port.pp$Stage;
let tempLength = port.pp$TempLength;
let tempPointer = port.pp$TempPointer;
for (let p = from; p < to; ) {
if (tempLength <= tempPointer) {
let mm = data3;
let m0 = data2;
let m1 = data1;
let m2, m3;
if (pointer < length) {
let i = stage + buffer[pointer++];
m2 = data = max2 (-0.5, min2 (0.5, data + adpcmLowerTable[i]));
m3 = data = max2 (-0.5, min2 (0.5, data + adpcmUpperTable[i]));
stage = adpcmNextTable[i];
} else if (data != 0) {
m2 = m3 = data;
} else {
port.pp$Running = false;
break;
}
if (data < 0) {
data += 1 / 8192;
} else if (0 < data) {
data -= 1 / 8192;
}
switch (rateNumber) {
case 0:
tempBuffer[ 0] = -0.02746582 * mm + 0.99060059 * m0 + 0.03869629 * m1 - 0.00183105 * m2;
tempBuffer[ 1] = -0.04785156 * mm + 0.96386719 * m0 + 0.09082031 * m1 - 0.00683594 * m2;
tempBuffer[ 2] = -0.06188965 * mm + 0.92199707 * m0 + 0.15417480 * m1 - 0.01428223 * m2;
tempBuffer[ 3] = -0.07031250 * mm + 0.86718750 * m0 + 0.22656250 * m1 - 0.02343750 * m2;
tempBuffer[ 4] = -0.07385254 * mm + 0.80163574 * m0 + 0.30578613 * m1 - 0.03356934 * m2;
tempBuffer[ 5] = -0.07324219 * mm + 0.72753906 * m0 + 0.38964844 * m1 - 0.04394531 * m2;
tempBuffer[ 6] = -0.06921387 * mm + 0.64709473 * m0 + 0.47595215 * m1 - 0.05383301 * m2;
tempBuffer[ 7] = -0.06250000 * mm + 0.56250000 * m0 + 0.56250000 * m1 - 0.06250000 * m2;
tempBuffer[ 8] = -0.05383301 * mm + 0.47595215 * m0 + 0.64709473 * m1 - 0.06921387 * m2;
tempBuffer[ 9] = -0.04394531 * mm + 0.38964844 * m0 + 0.72753906 * m1 - 0.07324219 * m2;
tempBuffer[10] = -0.03356934 * mm + 0.30578613 * m0 + 0.80163574 * m1 - 0.07385254 * m2;
tempBuffer[11] = -0.02343750 * mm + 0.22656250 * m0 + 0.86718750 * m1 - 0.07031250 * m2;
tempBuffer[12] = -0.01428223 * mm + 0.15417480 * m0 + 0.92199707 * m1 - 0.06188965 * m2;
tempBuffer[13] = -0.00683594 * mm + 0.09082031 * m0 + 0.96386719 * m1 - 0.04785156 * m2;
tempBuffer[14] = -0.00183105 * mm + 0.03869629 * m0 + 0.99060059 * m1 - 0.02746582 * m2;
tempBuffer[15] = m1;
tempBuffer[16] = -0.02746582 * m0 + 0.99060059 * m1 + 0.03869629 * m2 - 0.00183105 * m3;
tempBuffer[17] = -0.04785156 * m0 + 0.96386719 * m1 + 0.09082031 * m2 - 0.00683594 * m3;
tempBuffer[18] = -0.06188965 * m0 + 0.92199707 * m1 + 0.15417480 * m2 - 0.01428223 * m3;
tempBuffer[19] = -0.07031250 * m0 + 0.86718750 * m1 + 0.22656250 * m2 - 0.02343750 * m3;
tempBuffer[20] = -0.07385254 * m0 + 0.80163574 * m1 + 0.30578613 * m2 - 0.03356934 * m3;
tempBuffer[21] = -0.07324219 * m0 + 0.72753906 * m1 + 0.38964844 * m2 - 0.04394531 * m3;
tempBuffer[22] = -0.06921387 * m0 + 0.64709473 * m1 + 0.47595215 * m2 - 0.05383301 * m3;
tempBuffer[23] = -0.06250000 * m0 + 0.56250000 * m1 + 0.56250000 * m2 - 0.06250000 * m3;
tempBuffer[24] = -0.05383301 * m0 + 0.47595215 * m1 + 0.64709473 * m2 - 0.06921387 * m3;
tempBuffer[25] = -0.04394531 * m0 + 0.38964844 * m1 + 0.72753906 * m2 - 0.07324219 * m3;
tempBuffer[26] = -0.03356934 * m0 + 0.30578613 * m1 + 0.80163574 * m2 - 0.07385254 * m3;
tempBuffer[27] = -0.02343750 * m0 + 0.22656250 * m1 + 0.86718750 * m2 - 0.07031250 * m3;
tempBuffer[28] = -0.01428223 * m0 + 0.15417480 * m1 + 0.92199707 * m2 - 0.06188965 * m3;
tempBuffer[29] = -0.00683594 * m0 + 0.09082031 * m1 + 0.96386719 * m2 - 0.04785156 * m3;
tempBuffer[30] = -0.00183105 * m0 + 0.03869629 * m1 + 0.99060059 * m2 - 0.02746582 * m3;
tempBuffer[31] = m2;
tempLength = 32;
break;
case 1:
tempBuffer[ 0] = -0.03501157 * mm + 0.98350694 * m0 + 0.05468750 * m1 - 0.00318287 * m2;
tempBuffer[ 1] = -0.05787037 * mm + 0.93750000 * m0 + 0.13194444 * m1 - 0.01157407 * m2;
tempBuffer[ 2] = -0.07031250 * mm + 0.86718750 * m0 + 0.22656250 * m1 - 0.02343750 * m2;
tempBuffer[ 3] = -0.07407407 * mm + 0.77777778 * m0 + 0.33333333 * m1 - 0.03703704 * m2;
tempBuffer[ 4] = -0.07089120 * mm + 0.67447917 * m0 + 0.44704861 * m1 - 0.05063657 * m2;
tempBuffer[ 5] = -0.06250000 * mm + 0.56250000 * m0 + 0.56250000 * m1 - 0.06250000 * m2;
tempBuffer[ 6] = -0.05063657 * mm + 0.44704861 * m0 + 0.67447917 * m1 - 0.07089120 * m2;
tempBuffer[ 7] = -0.03703704 * mm + 0.33333333 * m0 + 0.77777778 * m1 - 0.07407407 * m2;
tempBuffer[ 8] = -0.02343750 * mm + 0.22656250 * m0 + 0.86718750 * m1 - 0.07031250 * m2;
tempBuffer[ 9] = -0.01157407 * mm + 0.13194444 * m0 + 0.93750000 * m1 - 0.05787037 * m2;
tempBuffer[10] = -0.00318287 * mm + 0.05468750 * m0 + 0.98350694 * m1 - 0.03501157 * m2;
tempBuffer[11] = m1;
tempBuffer[12] = -0.03501157 * m0 + 0.98350694 * m1 + 0.05468750 * m2 - 0.00318287 * m3;
tempBuffer[13] = -0.05787037 * m0 + 0.93750000 * m1 + 0.13194444 * m2 - 0.01157407 * m3;
tempBuffer[14] = -0.07031250 * m0 + 0.86718750 * m1 + 0.22656250 * m2 - 0.02343750 * m3;
tempBuffer[15] = -0.07407407 * m0 + 0.77777778 * m1 + 0.33333333 * m2 - 0.03703704 * m3;
tempBuffer[16] = -0.07089120 * m0 + 0.67447917 * m1 + 0.44704861 * m2 - 0.05063657 * m3;
tempBuffer[17] = -0.06250000 * m0 + 0.56250000 * m1 + 0.56250000 * m2 - 0.06250000 * m3;
tempBuffer[18] = -0.05063657 * m0 + 0.44704861 * m1 + 0.67447917 * m2 - 0.07089120 * m3;
tempBuffer[19] = -0.03703704 * m0 + 0.33333333 * m1 + 0.77777778 * m2 - 0.07407407 * m3;
tempBuffer[20] = -0.02343750 * m0 + 0.22656250 * m1 + 0.86718750 * m2 - 0.07031250 * m3;
tempBuffer[21] = -0.01157407 * m0 + 0.13194444 * m1 + 0.93750000 * m2 - 0.05787037 * m3;
tempBuffer[22] = -0.00318287 * m0 + 0.05468750 * m1 + 0.98350694 * m2 - 0.03501157 * m3;
tempBuffer[23] = m2;
tempLength = 24;
break;
case 2:
tempBuffer[ 0] = -0.04785156 * mm + 0.96386719 * m0 + 0.09082031 * m1 - 0.00683594 * m2;
tempBuffer[ 1] = -0.07031250 * mm + 0.86718750 * m0 + 0.22656250 * m1 - 0.02343750 * m2;
tempBuffer[ 2] = -0.07324219 * mm + 0.72753906 * m0 + 0.38964844 * m1 - 0.04394531 * m2;
tempBuffer[ 3] = -0.06250000 * mm + 0.56250000 * m0 + 0.56250000 * m1 - 0.06250000 * m2;
tempBuffer[ 4] = -0.04394531 * mm + 0.38964844 * m0 + 0.72753906 * m1 - 0.07324219 * m2;
tempBuffer[ 5] = -0.02343750 * mm + 0.22656250 * m0 + 0.86718750 * m1 - 0.07031250 * m2;
tempBuffer[ 6] = -0.00683594 * mm + 0.09082031 * m0 + 0.96386719 * m1 - 0.04785156 * m2;
tempBuffer[ 7] = m1;
tempBuffer[ 8] = -0.04785156 * m0 + 0.96386719 * m1 + 0.09082031 * m2 - 0.00683594 * m3;
tempBuffer[ 9] = -0.07031250 * m0 + 0.86718750 * m1 + 0.22656250 * m2 - 0.02343750 * m3;
tempBuffer[10] = -0.07324219 * m0 + 0.72753906 * m1 + 0.38964844 * m2 - 0.04394531 * m3;
tempBuffer[11] = -0.06250000 * m0 + 0.56250000 * m1 + 0.56250000 * m2 - 0.06250000 * m3;
tempBuffer[12] = -0.04394531 * m0 + 0.38964844 * m1 + 0.72753906 * m2 - 0.07324219 * m3;
tempBuffer[13] = -0.02343750 * m0 + 0.22656250 * m1 + 0.86718750 * m2 - 0.07031250 * m3;
tempBuffer[14] = -0.00683594 * m0 + 0.09082031 * m1 + 0.96386719 * m2 - 0.04785156 * m3;
tempBuffer[15] = m2;
tempLength = 16;
break;
case 3:
tempBuffer[ 0] = -0.05787037 * mm + 0.93750000 * m0 + 0.13194444 * m1 - 0.01157407 * m2;
tempBuffer[ 1] = -0.07407407 * mm + 0.77777778 * m0 + 0.33333333 * m1 - 0.03703704 * m2;
tempBuffer[ 2] = -0.06250000 * mm + 0.56250000 * m0 + 0.56250000 * m1 - 0.06250000 * m2;
tempBuffer[ 3] = -0.03703704 * mm + 0.33333333 * m0 + 0.77777778 * m1 - 0.07407407 * m2;
tempBuffer[ 4] = -0.01157407 * mm + 0.13194444 * m0 + 0.93750000 * m1 - 0.05787037 * m2;
tempBuffer[ 5] = m1;
tempBuffer[ 6] = -0.05787037 * m0 + 0.93750000 * m1 + 0.13194444 * m2 - 0.01157407 * m3;
tempBuffer[ 7] = -0.07407407 * m0 + 0.77777778 * m1 + 0.33333333 * m2 - 0.03703704 * m3;
tempBuffer[ 8] = -0.06250000 * m0 + 0.56250000 * m1 + 0.56250000 * m2 - 0.06250000 * m3;
tempBuffer[ 9] = -0.03703704 * m0 + 0.33333333 * m1 + 0.77777778 * m2 - 0.07407407 * m3;
tempBuffer[10] = -0.01157407 * m0 + 0.13194444 * m1 + 0.93750000 * m2 - 0.05787037 * m3;
tempBuffer[11] = m2;
tempLength = 12;
break;
case 4:
tempBuffer[ 0] = -0.07031250 * mm + 0.86718750 * m0 + 0.22656250 * m1 - 0.02343750 * m2;
tempBuffer[ 1] = -0.06250000 * mm + 0.56250000 * m0 + 0.56250000 * m1 - 0.06250000 * m2;
tempBuffer[ 2] = -0.02343750 * mm + 0.22656250 * m0 + 0.86718750 * m1 - 0.07031250 * m2;
tempBuffer[ 3] = m1;
tempBuffer[ 4] = -0.07031250 * m0 + 0.86718750 * m1 + 0.22656250 * m2 - 0.02343750 * m3;
tempBuffer[ 5] = -0.06250000 * m0 + 0.56250000 * m1 + 0.56250000 * m2 - 0.06250000 * m3;
tempBuffer[ 6] = -0.02343750 * m0 + 0.22656250 * m1 + 0.86718750 * m2 - 0.07031250 * m3;
tempBuffer[ 7] = m2;
tempLength = 8;
break;
case 5:
tempBuffer[ 0] = -0.07407407 * mm + 0.77777778 * m0 + 0.33333333 * m1 - 0.03703704 * m2;
tempBuffer[ 1] = -0.03703704 * mm + 0.33333333 * m0 + 0.77777778 * m1 - 0.07407407 * m2;
tempBuffer[ 2] = m1;
tempBuffer[ 3] = -0.07407407 * m0 + 0.77777778 * m1 + 0.33333333 * m2 - 0.03703704 * m3;
tempBuffer[ 4] = -0.03703704 * m0 + 0.33333333 * m1 + 0.77777778 * m2 - 0.07407407 * m3;
tempBuffer[ 5] = m2;
tempLength = 6;
break;
case 6:
tempBuffer[ 0] = -0.06250000 * mm + 0.56250000 * m0 + 0.56250000 * m1 - 0.06250000 * m2;
tempBuffer[ 1] = m1;
tempBuffer[ 2] = -0.06250000 * m0 + 0.56250000 * m1 + 0.56250000 * m2 - 0.06250000 * m3;
tempBuffer[ 3] = m2;
tempLength = 4;
break;
}
data3 = m1;
data2 = m2;
data1 = m3;
tempPointer = 0;
}
let tempPointerTo = tempPointer + min2 (tempLength, to - p);
if (panLeft && panRight) {
for (let q = tempPointer; q < tempPointerTo; q++) {
let t = tempBuffer[q];
internalBufferLeft[p] += t;
internalBufferRight[p++] += t;
}
} else if (panLeft) {
for (let q = tempPointer; q < tempPointerTo; q++) {
internalBufferLeft[p++] += tempBuffer[q];
}
} else if (panRight) {
for (let q = tempPointer; q < tempPointerTo; q++) {
internalBufferRight[p++] = tempBuffer[q];
}
} else {
p += tempPointerTo - tempPointer;
}
tempPointer = tempPointerTo;
}
port.pp$Pointer = pointer;
port.pp$Data = data;
port.pp$Data1 = data1;
port.pp$Data2 = data2;
port.pp$Data3 = data3;
port.pp$Stage = stage;
port.pp$TempLength = tempLength;
port.pp$TempPointer = tempPointer;
}
}
function audioAdvance (from, to) {
internalBufferLeft.fill (0, from, to);
internalBufferRight.fill (0, from, to);
opmAdvance (from, to);
pcmAdvance (from, to);
}
let commandQueue;
let commandTime;
function commandComparator (x, y) {
return x.t - y.t;
}
function addCommand (command) {
let l = 0;
let r = commandQueue.length;
while (l < r) {
let m = (l + r) >> 1;
if (commandComparator (commandQueue[m], command) <= 0) {
l = m + 1;
} else {
r = m;
}
}
commandQueue.splice (l, 0, command);
}
function removeCommand (c, p) {
for (let i = 0; i < commandQueue.length; i++) {
if (commandQueue[i].c == c &&
commandQueue[i].p == p) {
commandQueue.splice (i, 1);
break;
}
}
}
function execCommand (command) {
commandTime = command.t;
switch (command.c) {
case "opmset":
opmSet (opmPortArray[command.p], command.a, command.d);
break;
case "opminta":
opmIntA (opmPortArray[command.p]);
break;