public void Init(byte[] instrData) { if (_ready) { Reset(); return; } var pos = 0; if (instrData != null) { for (int i = 0; i < 6; i++) { _rhChan[i].data = instrData; _rhChan[i].dataOffset = instrData.ToUInt16BigEndian(pos); pos += 2; _rhChan[i].size = instrData.ToUInt16BigEndian(pos); pos += 2; } Reset(); _ready = true; } else { for (int i = 0; i < 6; i++) { _rhChan[i] = new RhtChannel(); } _ready = false; } }
public void NextTick(int[] buffer, int offset, int bufferSize) { if (!_ready) { return; } for (var i = 0; i < bufferSize; i++) { _timer += _tickLength; while (_timer > _rtt) { _timer -= _rtt; for (int ii = 0; ii < 6; ii++) { RhtChannel s = _rhChan[ii]; if (s.active) { RecalcOuput(s); if (s.decStep != 0) { AdvanceInput(s); if (s.posOffset == s.endOffset) { s.active = false; } } s.decStep ^= 1; } } } int finOut = 0; for (int ii = 0; ii < 6; ii++) { if (_rhChan[ii].active) { finOut += _rhChan[ii].@out; } } finOut <<= 1; if ((1 & _volMaskA) != 0) { finOut = (finOut * _volumeA) / Mixer.MaxMixerVolume; } if ((1 & _volMaskB) != 0) { finOut = (finOut * _volumeB) / Mixer.MaxMixerVolume; } buffer[offset + (i << 1)] += finOut; buffer[offset + (i << 1) + 1] += finOut; } }
void RecalcOuput(RhtChannel ins) { int s = _totalLevel + ins.level; int x = s > 62 ? 0 : (1 + (s >> 3)); int y = s > 62 ? 0 : (15 - (s & 7)); ins.@out = ((ins.samples[ins.decStep] * y) >> x) & ~3; }
void AdvanceInput(RhtChannel ins) { sbyte cur = (sbyte)ins.data[ins.posOffset++]; for (int i = 0; i < 2; i++) { int b = (2 * (cur & 7) + 1) * stepTable[ins.decState] / 8; ins.samples[i] = (short)ScummHelper.Clip(ins.samples[i ^ 1] + ((cur & 8) != 0 ? b : -b), -2048, 2047); ins.decState = (sbyte)ScummHelper.Clip(ins.decState + adjustIndex[cur & 7], 0, 48); cur >>= 4; } }
public void WriteReg(byte address, byte value) { if (!_ready) { return; } byte h = (byte)(address >> 4); byte l = (byte)(address & 15); if (address > 15) { _reg[address](value); } if (address == 0) { if ((value & 0x80) != 0) { //key off for (int i = 0; i < 6; i++) { if (((value >> i) & 1) != 0) { _rhChan[i].active = false; } } } else { //key on for (int i = 0; i < 6; i++) { if (((value >> i) & 1) != 0) { RhtChannel s = _rhChan[i]; s.posOffset = s.startOffset; s.active = true; s.@out = 0; s.samples[0] = s.samples[1] = 0; s.decStep = 1; s.decState = 0; } } } } else if (address == 1) { // total level _totalLevel = (byte)((value & 63) ^ 63); for (int i = 0; i < 6; i++) { RecalcOuput(_rhChan[i]); } } else if (h == 0 && ((l & 8) != 0)) { // instrument level l &= 7; _rhChan[l].level = (byte)((value & 0x1f) ^ 0x1f); RecalcOuput(_rhChan[l]); } else if ((h & 3) != 0) { l &= 7; if (h == 1) { // set start offset _rhChan[l].startOffset = _rhChan[l].dataOffset + ((_rhChan[l].startPosH << 8 | _rhChan[l].startPosL) << 8); } else if (h == 2) { // set end offset _rhChan[l].endOffset = _rhChan[l].dataOffset + ((_rhChan[l].endPosH << 8 | _rhChan[l].endPosL) << 8) + 255; } } }