protected override bool HandleSubTags(ref int offset) { if (_tbufferSize - offset >= 8) { var type = System.Text.Encoding.UTF8.GetString(_tbuffer, offset, 4); var size = ScummHelper.SwapBytes(BitConverter.ToUInt32(_tbuffer, offset + 4)); var available_size = _tbufferSize - offset; switch (type) { case "MAP ": _inData = false; if (available_size >= (size + 8)) { var tmp = new byte[_tbuffer.Length - offset]; Array.Copy(_tbuffer, offset, tmp, 0, tmp.Length); HandleMap(tmp); } break; case "DATA": _inData = true; _dataSize = (int)size; offset += 8; { int reqsize = 1; if (_channels == 2) { reqsize *= 2; } if (_bitsize == 16) { reqsize *= 2; } else if (_bitsize == 12) { if (reqsize > 1) { reqsize = reqsize * 3 / 2; } else { reqsize = 3; } } if ((size % reqsize) != 0) { Debug.WriteLine("Invalid iMUS sound data size : ({0} %% {1}) != 0, correcting...", size, reqsize); size += (uint)(3 - (size % reqsize)); } } return(false); // default: // Console.Error.WriteLine("unknown Chunk in iMUS track : {0} ", type); // break; } offset += (int)(size + 8); return(true); } return(false); }
protected virtual ColorCycle[] ReadCYCL() { var colorCycle = new ColorCycle[16]; for (int i = 0; i < 16; i++) { var delay = ScummHelper.SwapBytes(_reader.ReadUInt16()); var start = _reader.ReadByte(); var end = _reader.ReadByte(); colorCycle[i] = new ColorCycle(); if (delay == 0 || delay == 0x0aaa || start >= end) { continue; } colorCycle[i].Counter = 0; colorCycle[i].Delay = (ushort)(16384 / delay); colorCycle[i].Flags = 2; colorCycle[i].Start = start; colorCycle[i].End = end; } return(colorCycle); }
bool HandleMap(byte[] data) { // Read the chunk size & skip over the chunk header var size = ScummHelper.SwapBytes(BitConverter.ToUInt32(data, 4)); var i = 8; while (size > 0) { var subType = System.Text.Encoding.UTF8.GetString(data, i, 4); var subSize = ScummHelper.SwapBytes(BitConverter.ToUInt32(data, i + 4)); i += 8; size -= 8; switch (subType) { case "FRMT": // if (subSize != 20) // Console.Error.WriteLine("invalid size for FRMT Chunk"); //uint32 imuse_start = READ_BE_UINT32(data); //uint32 unk = READ_BE_UINT32(data+4); _bitsize = (int)ScummHelper.SwapBytes(BitConverter.ToUInt32(data, i + 8)); _rate = (int)ScummHelper.SwapBytes(BitConverter.ToUInt32(data, i + 12)); _channels = (int)ScummHelper.SwapBytes(BitConverter.ToUInt32(data, i + 16)); Debug.Assert(_channels == 1 || _channels == 2); break; case "TEXT": // Ignore this break; case "REGN": // if (subSize != 8) // Console.Error.WriteLine("invalid size for REGN Chunk"); break; case "STOP": // if (subSize != 4) // Console.Error.WriteLine("invalid size for STOP Chunk"); break; // default: // Console.Error.WriteLine("Unknown iMUS subChunk found : {0}, {1}", subType, subSize); // break; } i += (int)subSize; size -= subSize; } return(true); }
short ReadEndianSample(byte[] ptr, int offset) { ushort value; if (_is16Bit) { value = _isLE ? BitConverter.ToUInt16(ptr, offset) : ScummHelper.SwapBytes(BitConverter.ToUInt16(ptr, offset)); } else { value = (ushort)(ptr[offset] << 8); } if (_isUnsigned) { value ^= 0x8000; } return((short)value); }
public static int Decode12BitsSample(byte[] src, out byte[] dst, int size) { int loop_size = size / 3; int s_size = loop_size * 4; dst = new byte[s_size]; var i = 0; var ptr = 0; int tmp; while ((loop_size--) != 0) { byte v1 = src[i++]; byte v2 = src[i++]; byte v3 = src[i++]; tmp = ((((v2 & 0x0f) << 8) | v1) << 4) - 0x8000; Array.Copy(BitConverter.GetBytes(ScummHelper.SwapBytes((ushort)tmp)), 0, dst, ptr, 2); ptr += 2; tmp = ((((v2 & 0xf0) << 4) | v3) << 4) - 0x8000; Array.Copy(BitConverter.GetBytes(ScummHelper.SwapBytes((ushort)tmp)), 0, dst, ptr, 2); ptr += 2; } return(s_size); }
byte DrawLimb(Actor a, int limb) { var cost = a.Cost; byte result = 0; var lastDx = 0; var lastDy = 0; if (SkipLimbs) { return(0); } if (cost.Active[limb] == 0 || ((cost.Stopped & (1 << limb)) != 0)) { return(0); } var p = cost.Curpos[limb]; AkosOpcode code = (AkosOpcode)aksq[p]; if (((ushort)code & 0x80) != 0) { code = (AkosOpcode)ScummHelper.SwapBytes(BitConverter.ToUInt16(aksq, p)); } if (code == AkosOpcode.C021 || code == AkosOpcode.C022) { ushort s = (ushort)(cost.Curpos[limb] + 4); var extra = aksq[p + 3]; byte n = extra; p += (ushort)(extra + 2); code = (code == AkosOpcode.C021) ? AkosOpcode.ComplexChan : AkosOpcode.ComplexChan2; } if (code == AkosOpcode.Return || code == AkosOpcode.EndSeq) { return(0); } if (code != AkosOpcode.ComplexChan && code != AkosOpcode.ComplexChan2) { var off = ResourceFile7.ToStructure <AkosOffset>(akos, (int)(akof + 6 * ((ushort)code & 0xFFF))); Debug.Assert(((ushort)code & 0xFFF) * 6 < ScummHelper.SwapBytes(BitConverter.ToUInt32(akos, (int)(akof - 4))) - 8); Debug.Assert(((ushort)code & 0x7000) == 0); _srcptr = (int)off.akcd; Debug.Assert(_srcptr < akcd.Length); var costumeInfo = ResourceFile7.ToStructure <CostumeInfo>(akos, (int)(akci + off.akci)); _width = costumeInfo.width; _height = costumeInfo.height; var xmoveCur = _xmove + costumeInfo.rel_x; var ymoveCur = _ymove + costumeInfo.rel_y; _xmove += costumeInfo.move_x; _ymove -= costumeInfo.move_y; switch (_codec) { case 1: result |= Codec1(xmoveCur, ymoveCur); break; case 5: result |= Codec5(xmoveCur, ymoveCur); break; case 16: result |= Codec16(xmoveCur, ymoveCur); break; default: throw new InvalidOperationException(string.Format("akos_drawLimb: invalid _codec {0}", _codec)); } } else { if (code == AkosOpcode.ComplexChan2) { lastDx = BitConverter.ToInt16(aksq, p + 2); lastDy = BitConverter.ToInt16(aksq, p + 4); p += 4; } var extra = aksq[p + 2]; p += 3; for (var i = 0; i != extra; i++) { code = (AkosOpcode)aksq[p + 4]; if (((ushort)code & 0x80) != 0) { code = (AkosOpcode)ScummHelper.SwapBytes(BitConverter.ToUInt16(aksq, p + 4)); } var off = ResourceFile7.ToStructure <AkosOffset>(akos, (int)(akof + 6 * ((ushort)code & 0xFFF))); _srcptr = (int)off.akcd; var costumeInfo = ResourceFile7.ToStructure <CostumeInfo>(akos, (int)(akci + off.akci)); _width = costumeInfo.width; _height = costumeInfo.height; var xmoveCur = _xmove + BitConverter.ToInt16(aksq, p + 0); var ymoveCur = _ymove + BitConverter.ToInt16(aksq, p + 2); if (i == extra - 1) { _xmove += lastDx; _ymove -= lastDy; } p += ((aksq[p + 4] & 0x80) != 0) ? (ushort)6 : (ushort)5; switch (_codec) { case 1: result |= Codec1(xmoveCur, ymoveCur); break; case 5: result |= Codec5(xmoveCur, ymoveCur); break; case 16: result |= Codec16(xmoveCur, ymoveCur); break; case 32: result |= Codec32(xmoveCur, ymoveCur); break; default: throw new InvalidOperationException(string.Format("akos_drawLimb: invalid _codec {0}", _codec)); } } } return(result); }
protected override bool HandleSubTags(ref int offset) { if (_tbufferSize - offset >= 8) { var type = System.Text.Encoding.UTF8.GetString(_tbuffer, offset, 4); var size = ScummHelper.SwapBytes(BitConverter.ToUInt32(_tbuffer, offset + 4)); var available_size = _tbufferSize - offset; switch (type) { case "STRK": _inData = false; if (available_size >= (size + 8)) { var subSize = ScummHelper.SwapBytes(BitConverter.ToUInt32(_tbuffer, offset + 4)); if (subSize != 14 && subSize != 10) { throw new NotSupportedException(string.Format("STRK has an invalid size : {0}", subSize)); } } else { return(false); } break; case "SMRK": _inData = false; if (available_size >= (size + 8)) { _markReached = true; } else { return(false); } break; case "SHDR": _inData = false; if (available_size >= (size + 8)) { var subSize = ScummHelper.SwapBytes(BitConverter.ToUInt32(_tbuffer, offset + 4)); if (subSize != 4) { throw new NotSupportedException(string.Format("SHDR has an invalid size : {0}", subSize)); } } else { return(false); } break; case "SDAT": _inData = true; _dataSize = (int)size; offset += 8; return(false); default: throw new NotSupportedException(string.Format("unknown Chunk in SAUD track : {0}", type)); } offset += (int)(size + 8); return(true); } return(false); }
void LoadFont(string filename) { byte[] dataSrc; using (var file = ServiceLocator.FileStorage.OpenFileRead(filename)) { var reader = new BinaryReader(file); var tag = System.Text.Encoding.UTF8.GetString(reader.ReadBytes(4)); if (tag != "ANIM") { throw new InvalidOperationException("NutRenderer.LoadFont() there is no ANIM chunk in font header"); } var length = (int)reader.ReadUInt32BigEndian(); dataSrc = reader.ReadBytes(length); } if (System.Text.Encoding.UTF8.GetString(dataSrc, 0, 4) != "AHDR") { throw new InvalidOperationException("NutRenderer::loadFont() there is no AHDR chunk in font header"); } // We pre-decode the font, which may seem wasteful at first. Actually, // the memory needed for just the decoded glyphs is smaller than the // whole of the undecoded font file. _numChars = BitConverter.ToUInt16(dataSrc, 10); Debug.Assert(_numChars <= _chars.Length); _paletteMap = new byte[256]; var offset = 0; var decodedLength = 0; for (var l = 0; l < _numChars; l++) { offset += (int)ScummHelper.SwapBytes(BitConverter.ToUInt32(dataSrc, offset + 4)) + 16; int width = BitConverter.ToUInt16(dataSrc, offset + 14); int height = BitConverter.ToUInt16(dataSrc, offset + 16); int size = width * height; decodedLength += size; if (size > _maxCharSize) { _maxCharSize = size; } } Debug.WriteLine("NutRenderer::loadFont('{0}') - decodedLength = {1}", filename, decodedLength); _decodedData = new byte[decodedLength]; var decodedPos = 0; offset = 0; for (var l = 0; l < _numChars; l++) { offset += (int)ScummHelper.SwapBytes(BitConverter.ToUInt32(dataSrc, offset + 4)) + 8; if (System.Text.Encoding.UTF8.GetString(dataSrc, offset, 4) != "FRME") { throw new InvalidOperationException(string.Format("NutRenderer::loadFont({0}) there is no FRME chunk {1} (offset {2:X})", filename, l, offset)); } offset += 8; if (System.Text.Encoding.UTF8.GetString(dataSrc, offset, 4) != "FOBJ") { throw new InvalidOperationException(string.Format("NutRenderer::loadFont({0}) there is no FOBJ chunk in FRME chunk {1} (offset {2:X})", filename, l, offset)); } int codec = BitConverter.ToUInt16(dataSrc, offset + 8); // _chars[l].xoffs = READ_LE_UINT16(dataSrc + offset + 10); // _chars[l].yoffs = READ_LE_UINT16(dataSrc + offset + 12); _chars[l].Width = BitConverter.ToUInt16(dataSrc, offset + 14); _chars[l].Height = BitConverter.ToUInt16(dataSrc, offset + 16); _chars[l].Src = _decodedData; _chars[l].SrcOffset = decodedPos; decodedPos += (_chars[l].Width * _chars[l].Height); // If characters have transparency, then bytes just get skipped and // so there may appear some garbage. That's why we have to fill it // with a default color first. if (codec == 44) { for (int i = 0; i < _chars[l].Width * _chars[l].Height; i++) { _chars[l].Src[_chars[l].SrcOffset + i] = Smush44TransparentColor; } _paletteMap[Smush44TransparentColor] = 1; _chars[l].Transparency = Smush44TransparentColor; } else { for (int i = 0; i < _chars[l].Width * _chars[l].Height; i++) { _chars[l].Src[_chars[l].SrcOffset + i] = DefaultTransparentColor; } _paletteMap[DefaultTransparentColor] = 1; _chars[l].Transparency = DefaultTransparentColor; } switch (codec) { case 1: Codec1(_chars[l].Src, _chars[l].SrcOffset, dataSrc, offset + 22, _chars[l].Width, _chars[l].Height, _chars[l].Width); break; case 21: case 44: Codec21(_chars[l].Src, _chars[l].SrcOffset, dataSrc, offset + 22, _chars[l].Width, _chars[l].Height, _chars[l].Width); break; default: throw new InvalidOperationException(string.Format("NutRenderer::loadFont: unknown codec: {0}", codec)); } } // We have decoded the font. Now let's see if we can re-compress it to // a more compact format. Start by counting the number of colors. int numColors = 0; for (var l = 0; l < 256; l++) { if (_paletteMap[l] != 0) { if (numColors < _palette.Length) { _paletteMap[l] = (byte)numColors; _palette[numColors] = (byte)l; } numColors++; } } // Now _palette contains all the used colors, and _paletteMap maps the // real color to the palette index. if (numColors <= 2) { _bpp = 1; } else if (numColors <= 4) { _bpp = 2; } else if (numColors <= 16) { _bpp = 4; } else { _bpp = 8; } if (_bpp < 8) { int compressedLength = 0; for (var l = 0; l < 256; l++) { compressedLength += (((_bpp * _chars[l].Width + 7) / 8) * _chars[l].Height); } Debug.WriteLine("NutRenderer::loadFont('{0}') - compressedLength = {1} ({2} bpp)", filename, compressedLength, _bpp); var compressedData = new byte[compressedLength]; offset = 0; for (var l = 0; l < 256; l++) { var src = _chars[l].Src; var srcPos = _chars[l].SrcOffset; var dstPos = offset; int srcPitch = _chars[l].Width; int dstPitch = (_bpp * _chars[l].Width + 7) / 8; for (var h = 0; h < _chars[l].Height; h++) { byte bit = 0x80; var nextDst = dstPos + dstPitch; for (int w = 0; w < srcPitch; w++) { byte color = _paletteMap[src[srcPos + w]]; for (int i = 0; i < _bpp; i++) { if ((color & (1 << i)) != 0) { compressedData[dstPos] |= bit; } bit >>= 1; } if (bit == 0) { bit = 0x80; dstPos++; } } srcPos += srcPitch; dstPos = nextDst; } _chars[l].Src = compressedData; _chars[l].SrcOffset = offset; offset += (dstPitch * _chars[l].Height); } _decodedData = compressedData; _charBuffer = new byte[_maxCharSize]; } _paletteMap = null; }
static uint GetResSnd() { return(ScummHelper.SwapBytes(BitConverter.ToUInt32( System.Text.Encoding.UTF8.GetBytes("snd "), 0))); }
public void QueueCompressedBuffer(byte[] buffer, int bufferSize, int unpackedSize) { using (var ms = new MemoryStream(buffer, 0, bufferSize)) { var audioBS = BitStream.Create8Lsb(ms); bool dataPresent = audioBS.GetBit() != 0; if (!dataPresent) { return; } bool isStereo = audioBS.GetBit() != 0; Debug.Assert(isStereo == _audioInfo.isStereo); bool is16Bits = audioBS.GetBit() != 0; Debug.Assert(is16Bits == _audioInfo.is16Bits); int numBytes = 1 * (isStereo ? 2 : 1) * (is16Bits ? 2 : 1); byte[] unpackedBuffer = new byte[unpackedSize]; var curPointer = 0; var curPos = 0; SmallHuffmanTree[] audioTrees = new SmallHuffmanTree[4]; for (int k = 0; k < numBytes; k++) { audioTrees[k] = new SmallHuffmanTree(audioBS); } // Base values, stored as big endian int[] bases = new int[2]; if (isStereo) { if (is16Bits) { bases[1] = ScummHelper.SwapBytes((ushort)audioBS.GetBits(16)); } else { bases[1] = (int)audioBS.GetBits(8); } } if (is16Bits) { bases[0] = ScummHelper.SwapBytes((ushort)audioBS.GetBits(16)); } else { bases[0] = (int)audioBS.GetBits(8); } // The bases are the first samples, too for (int i = 0; i < (isStereo ? 2 : 1); i++, curPointer += (is16Bits ? 2 : 1), curPos += (is16Bits ? 2 : 1)) { if (is16Bits) { unpackedBuffer.WriteUInt16BigEndian(curPointer, (ushort)bases[i]); } else { unpackedBuffer[curPointer] = (byte)((bases[i] & 0xFF) ^ 0x80); } } // Next follow the deltas, which are added to the corresponding base values and // are stored as little endian // We store the unpacked bytes in big endian format while (curPos < unpackedSize) { // If the sample is stereo, the data is stored for the left and right channel, respectively // (the exact opposite to the base values) if (!is16Bits) { for (int k = 0; k < (isStereo ? 2 : 1); k++) { sbyte delta = (sbyte)((short)audioTrees[k].GetCode(audioBS)); bases[k] = (bases[k] + delta) & 0xFF; unpackedBuffer[curPointer++] = (byte)(bases[k] ^ 0x80); curPos++; } } else { for (int k = 0; k < (isStereo ? 2 : 1); k++) { byte lo = (byte)audioTrees[k * 2].GetCode(audioBS); byte hi = (byte)audioTrees[k * 2 + 1].GetCode(audioBS); bases[k] += (short)(lo | (hi << 8)); unpackedBuffer.WriteUInt16BigEndian(curPointer, (ushort)bases[k]); curPointer += 2; curPos += 2; } } } QueuePCM(unpackedBuffer, unpackedSize); } }
public uint ReadUInt32(uint value) { return(_isBigEndian ? ScummHelper.SwapBytes(value) : value); }
public short ReadInt16(short value) { return(_isBigEndian ? ScummHelper.SwapBytes(value) : value); }
public static bool IncreaseAnim(Actor a, int chan, byte[] aksq, byte[] akfo, int numakfo, ScummEngine vm) { byte active; int old_curpos, end; int curpos; bool flag_value, needRedraw; int tmp, tmp2; active = a.Cost.Active[chan]; end = a.Cost.End[chan]; old_curpos = curpos = a.Cost.Curpos[chan]; flag_value = false; needRedraw = false; do { var code = (AkosOpcode)aksq[curpos]; if (((ushort)code & 0x80) != 0) { code = (AkosOpcode)ScummHelper.SwapBytes(BitConverter.ToUInt16(aksq, curpos)); } switch (active) { case 6: case 8: switch (code) { case AkosOpcode.JumpIfSet: case AkosOpcode.AddVar: case AkosOpcode.SetVar: case AkosOpcode.SkipGE: case AkosOpcode.SkipG: case AkosOpcode.SkipLE: case AkosOpcode.SkipL: case AkosOpcode.SkipNE: case AkosOpcode.SkipE: case AkosOpcode.C016: case AkosOpcode.C017: case AkosOpcode.C018: case AkosOpcode.C019: curpos += 5; break; case AkosOpcode.JumpTable: case AkosOpcode.SetActorClip: case AkosOpcode.Ignore3: case AkosOpcode.Ignore2: case AkosOpcode.Ignore: case AkosOpcode.StartAnim: case AkosOpcode.StartVarAnim: case AkosOpcode.CmdQue3: case AkosOpcode.C042: case AkosOpcode.C044: case AkosOpcode.C0A3: curpos += 3; break; case AkosOpcode.SoundStuff: // if (Game.Heversion >= 61) // curpos += 6; // else curpos += 8; break; case AkosOpcode.Cmd3: case AkosOpcode.SetVarInActor: case AkosOpcode.SetDrawOffs: curpos += 6; break; case AkosOpcode.ClearFlag: case AkosOpcode.HideActor: case AkosOpcode.IncVar: case AkosOpcode.CmdQue3Quick: case AkosOpcode.Return: case AkosOpcode.EndSeq: curpos += 2; break; case AkosOpcode.JumpGE: case AkosOpcode.JumpG: case AkosOpcode.JumpLE: case AkosOpcode.JumpL: case AkosOpcode.JumpNE: case AkosOpcode.JumpE: case AkosOpcode.Random: curpos += 7; break; case AkosOpcode.Flip: case AkosOpcode.Jump: case AkosOpcode.StartAnimInActor: case AkosOpcode.C0A0: case AkosOpcode.C0A1: case AkosOpcode.C0A2: curpos += 4; break; case AkosOpcode.ComplexChan2: curpos += 4; curpos += 3; tmp = aksq[curpos - 1]; while (--tmp >= 0) { curpos += 4; curpos += ((aksq[curpos] & 0x80) != 0) ? 2 : 1; } break; // Fall through case AkosOpcode.ComplexChan: curpos += 3; tmp = aksq[curpos - 1]; while (--tmp >= 0) { curpos += 4; curpos += ((aksq[curpos] & 0x80) != 0) ? 2 : 1; } break; case AkosOpcode.C021: case AkosOpcode.C022: case AkosOpcode.C045: case AkosOpcode.C046: case AkosOpcode.C047: case AkosOpcode.C048: needRedraw = true; curpos += aksq[curpos + 2]; break; case AkosOpcode.C08E: akos_queCommand(7, a, GW(aksq, curpos, 2), 0, vm); curpos += 4; break; default: curpos += (((short)code & 0x8000) != 0) ? 2 : 1; break; } break; case 2: curpos += (((short)code & 0x8000) != 0) ? 2 : 1; if (curpos > end) { curpos = a.Cost.Start[chan]; } break; case 3: if (curpos != end) { curpos += (((short)code & 0x8000) != 0) ? 2 : 1; } break; } code = (AkosOpcode)aksq[curpos]; if (((short)code & 0x80) != 0) { code = (AkosOpcode)ScummHelper.SwapBytes(BitConverter.ToUInt16(aksq, curpos)); } if (flag_value && code != AkosOpcode.ClearFlag) { continue; } switch (code) { case AkosOpcode.StartAnimInActor: akos_queCommand(4, vm.Actors[a.GetAnimVar(GB(aksq, curpos, 2))], a.GetAnimVar(GB(aksq, curpos, 3)), 0, vm); continue; case AkosOpcode.Random: a.SetAnimVar(GB(aksq, curpos, 6), new Random().Next(GW(aksq, curpos, 2), GW(aksq, curpos, 4))); continue; case AkosOpcode.JumpGE: case AkosOpcode.JumpG: case AkosOpcode.JumpLE: case AkosOpcode.JumpL: case AkosOpcode.JumpNE: case AkosOpcode.JumpE: if (akos_compare(a.GetAnimVar(GB(aksq, curpos, 4)), GW(aksq, curpos, 5), (byte)(code - AkosOpcode.JumpStart))) { curpos = GUW(aksq, curpos, 2); break; } continue; case AkosOpcode.IncVar: a.SetAnimVar(0, a.GetAnimVar(0) + 1); continue; case AkosOpcode.SetVar: a.SetAnimVar(GB(aksq, curpos, 4), GW(aksq, curpos, 2)); continue; case AkosOpcode.AddVar: a.SetAnimVar(GB(aksq, curpos, 4), a.GetAnimVar(GB(aksq, curpos, 4)) + GW(aksq, curpos, 2)); continue; case AkosOpcode.Flip: a.Flip = GW(aksq, curpos, 2) != 0; continue; case AkosOpcode.CmdQue3: // if (Game.Heversion >= 61) // tmp = GB(aksq, curpos,2); // else tmp = GB(aksq, curpos, 2) - 1; if ((uint)tmp < 24) { akos_queCommand(3, a, a.Sounds[tmp], 0, vm); } continue; case AkosOpcode.CmdQue3Quick: akos_queCommand(3, a, a.Sounds[0], 0, vm); continue; case AkosOpcode.StartAnim: akos_queCommand(4, a, GB(aksq, curpos, 2), 0, vm); continue; case AkosOpcode.StartVarAnim: akos_queCommand(4, a, a.GetAnimVar(GB(aksq, curpos, 2)), 0, vm); continue; case AkosOpcode.SetVarInActor: vm.Actors[a.GetAnimVar(GB(aksq, curpos, 2))].SetAnimVar(GB(aksq, curpos, 3), GW(aksq, curpos, 4)); continue; case AkosOpcode.HideActor: akos_queCommand(1, a, 0, 0, vm); continue; case AkosOpcode.SetActorClip: akos_queCommand(5, a, GB(aksq, curpos, 2), 0, vm); continue; case AkosOpcode.SoundStuff: // if (_game.heversion >= 61) // continue; tmp = GB(aksq, curpos, 2) - 1; if (tmp >= 8) { continue; } tmp2 = GB(aksq, curpos, 4); if (tmp2 < 1 || tmp2 > 3) { throw new InvalidOperationException(string.Format("akos_increaseAnim:8 invalid code {0}", tmp2)); } akos_queCommand((byte)(tmp2 + 6), a, a.Sounds[tmp], GB(aksq, curpos, 6), vm); continue; case AkosOpcode.SetDrawOffs: akos_queCommand(6, a, GW(aksq, curpos, 2), GW(aksq, curpos, 4), vm); continue; case AkosOpcode.JumpTable: if (akfo == null) { throw new InvalidOperationException("akos_increaseAnim: no AKFO table"); } tmp = a.GetAnimVar(GB(aksq, curpos, 2)) - 1; // if (_game.heversion >= 80) // { // if (tmp < 0 || tmp > a.Cost.heJumpCountTable[chan] - 1) // error("akos_increaseAnim: invalid jump value %d", tmp); // curpos = READ_LE_UINT16(akfo + a.Cost.heJumpOffsetTable[chan] + tmp * 2); // } // else { if (tmp < 0 || tmp > numakfo - 1) { throw new InvalidOperationException(string.Format("akos_increaseAnim: invalid jump value {0}", tmp)); } curpos = BitConverter.ToUInt16(akfo, tmp); } break; case AkosOpcode.JumpIfSet: if (a.GetAnimVar(GB(aksq, curpos, 4)) == 0) { continue; } a.SetAnimVar(GB(aksq, curpos, 4), 0); curpos = GUW(aksq, curpos, 2); break; case AkosOpcode.ClearFlag: flag_value = false; continue; case AkosOpcode.Jump: curpos = GUW(aksq, curpos, 2); break; case AkosOpcode.Return: case AkosOpcode.EndSeq: case AkosOpcode.ComplexChan: case AkosOpcode.C08E: case AkosOpcode.ComplexChan2: break; case AkosOpcode.C021: case AkosOpcode.C022: needRedraw = true; break; case AkosOpcode.Cmd3: case AkosOpcode.Ignore: case AkosOpcode.Ignore3: continue; case AkosOpcode.Ignore2: // if (_game.heversion >= 71) // akos_queCommand(3, a, a._sound[a.GetAnimVar(GB(aksq, curpos,2))], 0); continue; case AkosOpcode.SkipE: case AkosOpcode.SkipNE: case AkosOpcode.SkipL: case AkosOpcode.SkipLE: case AkosOpcode.SkipG: case AkosOpcode.SkipGE: if (!akos_compare(a.GetAnimVar(GB(aksq, curpos, 4)), GW(aksq, curpos, 2), (byte)(code - AkosOpcode.SkipStart))) { flag_value = true; } continue; case AkosOpcode.C016: if (vm.Sound.IsSoundRunning(a.Sounds[a.GetAnimVar(GB(aksq, curpos, 4))])) { curpos = GUW(aksq, curpos, 2); break; } continue; case AkosOpcode.C017: if (!vm.Sound.IsSoundRunning(a.Sounds[a.GetAnimVar(GB(aksq, curpos, 4))])) { curpos = GUW(aksq, curpos, 2); break; } continue; case AkosOpcode.C018: if (vm.Sound.IsSoundRunning(a.Sounds[GB(aksq, curpos, 4)])) { curpos = GUW(aksq, curpos, 2); break; } continue; case AkosOpcode.C019: if (!vm.Sound.IsSoundRunning(a.Sounds[GB(aksq, curpos, 4)])) { curpos = GUW(aksq, curpos, 2); break; } continue; case AkosOpcode.C042: akos_queCommand(9, a, a.Sounds[GB(aksq, curpos, 2)], 0, vm); continue; case AkosOpcode.C044: akos_queCommand(9, a, a.Sounds[a.GetAnimVar(GB(aksq, curpos, 2))], 0, vm); continue; // case AkosOpcode.C045: // ((ActorHE*)a).SetUserCondition(GB(aksq, curpos, 3), a.GetAnimVar(GB(aksq, curpos, 4))); // continue; // case AkosOpcode.C046: // a.SetAnimVar(GB(aksq, curpos, 4), ((ActorHE*)a).isUserConditionSet(GB(aksq, curpos, 3))); // continue; // case AkosOpcode.C047: // ((ActorHE*)a).setTalkCondition(GB(aksq, curpos, 3)); // continue; // case AkosOpcode.C048: // a.setAnimVar(GB(aksq, curpos, 4), ((ActorHE*)a).isTalkConditionSet(GB(aksq, curpos, 3))); // continue; case AkosOpcode.C0A0: akos_queCommand(8, a, GB(aksq, curpos, 2), 0, vm); continue; // case AkosOpcode.C0A1: // if (((ActorHE*)a)._heTalking != 0) // { // curpos = GUW(aksq, curpos, 2); // break; // } // continue; // case AkosOpcode.C0A2: // if (((ActorHE*)a)._heTalking == 0) // { // curpos = GUW(aksq, curpos, 2); // break; // } // continue; case AkosOpcode.C0A3: akos_queCommand(8, a, a.GetAnimVar(GB(aksq, curpos, 2)), 0, vm); continue; case AkosOpcode.C0A4: if (vm.Variables[vm.VariableTalkActor.Value] != 0) { curpos = GUW(aksq, curpos, 2); break; } continue; case AkosOpcode.C0A5: if (vm.Variables[vm.VariableTalkActor.Value] == 0) { curpos = GUW(aksq, curpos, 2); break; } continue; default: if (((short)code & 0xC000) == 0xC000) { throw new InvalidOperationException(string.Format("Undefined uSweat token {0:X}", code)); } break; } break; } while (true); int code2 = aksq[curpos]; if ((code2 & 0x80) != 0) { code2 = ScummHelper.SwapBytes(BitConverter.ToUInt16(aksq, curpos)); } if (((code2 & 0xC000) == 0xC000) && code2 != (int)AkosOpcode.ComplexChan && code2 != (int)AkosOpcode.Return && code2 != (int)AkosOpcode.EndSeq && code2 != (int)AkosOpcode.C08E && code2 != (int)AkosOpcode.ComplexChan2 && code2 != (int)AkosOpcode.C021 && code2 != (int)AkosOpcode.C022) { throw new InvalidOperationException(string.Format("Ending with undefined uSweat token {0:X}", code2)); } a.Cost.Curpos[chan] = (ushort)curpos; if (needRedraw) { return(true); } else { return(curpos != old_curpos); } }
private UShortAccess UncompressSpeech(uint index, uint cSize, out uint size) { _cowFile.BaseStream.Seek(index, SeekOrigin.Begin); var fBuf = _cowFile.ReadBytes((int)cSize); uint headerPos = 0; while ((fBuf.ToUInt32BigEndian((int)headerPos) != ScummHelper.MakeTag('d', 'a', 't', 'a')) && (headerPos < 100)) { headerPos++; } UShortAccess srcData; if (headerPos < 100) { int resSize; uint srcPos; short length; cSize /= 2; headerPos += 4; // skip 'data' tag if (_cowMode != CowMode.CowDemo) { resSize = (int)(fBuf.ToUInt32((int)headerPos) >> 1); headerPos += 4; } else { // the demo speech files have the uncompressed size // embedded in the compressed stream *sigh* // // But not always, apparently. See bug #2182450. Is // there any way to figure out the size other than // decoding the sound in that case? if (fBuf[headerPos + 1] == 0) { if (fBuf.ToInt16((int)headerPos) == 1) { resSize = fBuf.ToInt16((int)(headerPos + 2)); resSize |= fBuf.ToInt16((int)(headerPos + 6)) << 16; } else { resSize = fBuf.ToInt32((int)(headerPos + 2)); } resSize >>= 1; } else { resSize = 0; srcData = new UShortAccess(fBuf); srcPos = headerPos >> 1; while (srcPos < cSize) { length = (short)srcData[(int)srcPos]; srcPos++; if (length < 0) { resSize -= length; srcPos++; } else { resSize += length; srcPos = (uint)(srcPos + length); } } } } Debug.Assert((headerPos & 1) == 0); srcData = new UShortAccess(fBuf); srcPos = headerPos >> 1; uint dstPos = 0; var dstData = new UShortAccess(new byte[resSize * 2]); int samplesLeft = resSize; while (srcPos < cSize && samplesLeft > 0) { length = (short)(_bigEndianSpeech ? ScummHelper.SwapBytes(srcData[(int)srcPos]) : srcData[(int)srcPos]); srcPos++; if (length < 0) { length = (short)-length; if (length > samplesLeft) { length = (short)samplesLeft; } short value; if (_bigEndianSpeech) { value = (short)ScummHelper.SwapBytes(srcData[(int)srcPos]); } else { value = (short)srcData[(int)srcPos]; } for (ushort cnt = 0; cnt < (ushort)length; cnt++) { dstData[(int)dstPos++] = (ushort)value; } srcPos++; } else { if (length > samplesLeft) { length = (short)samplesLeft; } if (_bigEndianSpeech) { for (ushort cnt = 0; cnt < length; cnt++) { dstData[(int)dstPos++] = ScummHelper.SwapBytes(srcData[(int)srcPos++]); } } else { Array.Copy(srcData.Data, (int)(srcData.Offset + srcPos * 2), dstData.Data, (int)(dstData.Offset + dstPos * 2), length * 2); dstPos = (uint)(dstPos + length); srcPos = (uint)(srcPos + length); } } samplesLeft -= length; } if (samplesLeft > 0) { dstData.Data.Set((int)(dstData.Offset + dstPos), 0, samplesLeft * 2); } if (_cowMode == CowMode.CowDemo) // demo has wave output size embedded in the compressed data { dstData.Data.WriteUInt32(dstData.Offset, 0); } size = (uint)(resSize * 2); CalcWaveVolume(dstData, resSize); return(dstData); } else { // TODO: warning("Sound::uncompressSpeech(): DATA tag not found in wave header"); size = 0; return(null); } }
public void PlaySound(ushort sound, ushort volume, byte channel) { if (channel == 0) { _mixer.StopID(SoundChannel0); } else { _mixer.StopID(SoundChannel1); } if (_soundData == null) { // TODO: warning //warning("Sound::playSound(%04X, %04X) called with a section having been loaded", sound, volume); return; } if (sound > _soundsTotal) { // TODO: debug //debug(5, "Sound::playSound %d ignored, only %d sfx in file", sound, _soundsTotal); return; } volume = (ushort)((volume & 0x7F) << 1); sound &= 0xFF; // Note: All those tables are big endian. Don't ask me why. *sigh* // Use the sample rate from game data, see bug #1507757. var sampleRate = _sampleRates.Data.ToUInt16BigEndian(_sampleRates.Offset + (sound << 2)); if (sampleRate > 11025) { sampleRate = 11025; } var dataOfs = ScummHelper.SwapBytes(_sfxInfo[((sound << 3) + 0) / 2]) << 4; int dataSize = ScummHelper.SwapBytes(_sfxInfo[((sound << 3) + 2) / 2]); int dataLoop = ScummHelper.SwapBytes(_sfxInfo[((sound << 3) + 6) / 2]); dataOfs += _sfxBaseOfs; var stream = new RawStream(AudioFlags.Unsigned, sampleRate, false, new MemoryStream(_soundData, dataOfs, dataSize)); IAudioStream output; if (dataLoop != 0) { var loopSta = dataSize - dataLoop; var loopEnd = dataSize; output = new SubLoopingAudioStream(stream, 0, new Timestamp(0, loopSta, sampleRate), new Timestamp(0, loopEnd, sampleRate), true); } else { output = stream; } if (channel == 0) { _ingameSound0 = _mixer.PlayStream(SoundType.SFX, output, SoundChannel0, volume, 0); } else { _ingameSound1 = _mixer.PlayStream(SoundType.SFX, output, SoundChannel1, volume, 0); } }