/// <summary> /// Loads a *.utk file, setting things up for decompression. /// Should always be called before DecompressFile(). /// </summary> /// <param name="Path">The path to the *.utk file to load.</param> public void LoadFile(string Path) { m_Reader = new BinaryReader(File.Open(Path, FileMode.Open)); m_ID = new string(m_Reader.ReadChars(4)); m_DecompressedSize = m_Reader.ReadUInt32(); m_WaveFormatXSize = m_Reader.ReadUInt32(); m_FormatTag = m_Reader.ReadUInt16(); m_NumChannels = m_Reader.ReadUInt16(); m_SamplesPerSec = m_Reader.ReadUInt32(); m_AvgBytesPerSec = m_Reader.ReadUInt32(); m_BlockAlign = m_Reader.ReadUInt16(); m_BitsPerSample = m_Reader.ReadUInt16(); m_AppendSize = m_Reader.ReadUInt32(); m_DecompressedStream = new MemoryStream(); m_Writer = new BinaryWriter(m_DecompressedStream); //Write wav-header. uint dwDataSize = m_DecompressedSize; uint dwFMTSize = 16; uint dwRIFFSize = 36 + dwDataSize; m_Writer.Write(new char[] { 'R', 'I', 'F', 'F' }); m_Writer.Write(dwRIFFSize); //Size of file minus this field and the above field. m_Writer.Write(new char[] { 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' }); m_Writer.Write(dwFMTSize); //Size of WAVEFORMATEX structure (all the data that comes after this field). m_Writer.Write(m_FormatTag); m_Writer.Write(m_NumChannels); m_Writer.Write(m_SamplesPerSec); m_Writer.Write(m_AvgBytesPerSec); m_Writer.Write(m_BlockAlign); m_Writer.Write(m_BitsPerSample); m_Writer.Write(new char[] { 'd', 'a', 't', 'a' }); m_Writer.Write(dwDataSize); UTKParams P = new UTKParams(); P.UnreadBitsValue = m_Reader.ReadByte(); P.UnreadBitsCount = 8; P.UseLattice = (int)ReadBits(P, 1); P.NoiseFloor = (uint)32 - ReadBits(P, 4); P.FixedCodeBook[0] = (ReadBits(P, 4) + 1) * 8; float S = (float)ReadBits(P, 6) / 1000 + 1.04f; for (int i = 1; i < 64; i++) P.FixedCodeBook[i] = P.FixedCodeBook[i - 1] * S; //memset(p->ImpulseTrain, 0, 12*sizeof(float)); Array.Clear(P.ImpulseTrain, 0, 12); //memset(p->R, 0, 12*sizeof(float)); Array.Clear(P.R, 0, 12); //memset(p->Delay, 0, 324*sizeof(float)); Array.Clear(P.Delay, 0, 324); uint Frames = (uint)(m_DecompressedSize / m_BlockAlign); UTKDecode(P, Frames); }
private void UTKDecode(UTKParams P, uint Frames) { while (Frames > 0) { uint BlockSize = (Frames > 432) ? 432 : Frames; DecompressBlock(ref P); for (uint i = 0; i < BlockSize; i++) { int value = Round(P.DecompressedBlock[i]); if (value < -32767) value = 32767; else if (value > 32768) value = 32768; //Writing out as byte seems to fix the filesize. m_Writer.Write((byte)((value & 0x00FF/*u*/) >> (8 * 0))); m_Writer.Write((byte)((value & 0xFF00/*u*/) >> (8 * 1))); } Frames -= BlockSize; } }
private unsafe void Synthesize(UTKParams P, int Sample, uint Blocks) { float[] Residual = new float[12]; uint Samples = Blocks*12; int offset = -1; fixed (float* C64 = &P.ImpulseTrain[0]) { PredictionFilter(C64, ref Residual); } while(Samples > 0) { Samples--; float x = P.DecompressedBlock[Sample]; for (int i = 0; i < 12; i++) { if (++offset == 12) offset = 0; x += P.R[offset] * Residual[i]; } P.R[offset--] = x; P.DecompressedBlock[Sample++] = x; } }
private byte ReadBits(UTKParams P, byte NumBits) { byte ReturnValue = (byte)((255 >> (8 - NumBits)) & P.UnreadBitsValue); P.UnreadBitsValue >>= NumBits; P.UnreadBitsCount -= NumBits; try { if (P.UnreadBitsCount < 8) { uint Value = (byte)m_Reader.ReadByte(); P.UnreadBitsValue |= (byte)(Value << P.UnreadBitsCount/* & 0xFF*/); P.UnreadBitsCount += 8; } } catch (EndOfStreamException) { return ReturnValue; } return ReturnValue; }
private unsafe void LatticeFilter(ref UTKParams P, int Voiced, float* Window, int Interval) { if (Voiced != 0) { int t = 0; int i = 0; while (i < 108) { uint code = m_UTKTable2[(t << 8) | (P.UnreadBitsValue & 0xFF)]; t = (code < 2 || code > 8) ? 1 : 0; ReadBits(P, m_UTKTable3[code]); if (code >= 4) { Window[i] = m_UTKTable4[code]; i += Interval; } else { if (code > 1) { int x = (int)ReadBits(P, 6) + 7; if (x > (108 - i) / Interval) x = (108 - i) / Interval; while(x > 0) { x--; Window[i] = 0; i += Interval; } } else { Window[i] = 7; while (ReadBits(P, 1) > 0) Window[i]++; if (ReadBits(P, 1) != 0) Window[i] *= -1; i += Interval; } } } } else { //Unvoiced signal; load noise int i; for (i = 0; i < 108; i += Interval) { byte b; switch (P.UnreadBitsValue & 3) { case 3: Window[i] = 2.0f; b = 2; break; case 1: Window[i] = -2.0f; b = 2; break; default: Window[i] = 0.0f; b = 1; break; } ReadBits(P, b); } } }
private unsafe void DecompressBlock(ref UTKParams P) { float[] Window = new float[118]; float[] Matrix = new float[12]; int Voiced = 0; //memset(&Window[0], 0, 5*sizeof(float)); Array.Clear(Window, 0, 5); //memset(&Window[113], 0, 5 * sizeof(float)); Array.Clear(Window, 113, 5); for (int i = 0; i < 12; i++) { uint result = ReadBits(P, (byte)((i < 4) ? 6 : 5)); if (i == 0 && P.NoiseFloor > result) Voiced++; Matrix[i] = (m_UTKTable1[result + ((i < 4) ? 0 : 16)] - P.ImpulseTrain[i]) / 4; } for (int i = 0; i < 4; i++) { float PitchGain, InnovationGain; int Phase = (int)ReadBits(P, 8); PitchGain = ((float)ReadBits(P, 4)) / 15; InnovationGain = P.FixedCodeBook[ReadBits(P, 6)]; if (P.UseLattice == 0) { fixed (float* Wnd = &Window[5]) { LatticeFilter(ref P, Voiced, Wnd, 1); } } else { int o = ReadBits(P, 1); //Order int y = ReadBits(P, 1); fixed (float* Wnd = &Window[5 + o]) { LatticeFilter(ref P, Voiced, Wnd, 2); } if (y != 0) { for (int j = 0; j < 108; j += 2) Window[6 - o + j] = 0; } else { //Vector quantization fixed (float* Wnd = &Window[6 - o]) { float* Z = Wnd; for (int j = 0; j < 54; j++, Z += 2) *Z = (Z[-5] + Z[+5]) * .0180326793f - (Z[-3] + Z[+3]) * .1145915613f + (Z[-1] + Z[+1]) * .5973859429f; InnovationGain /= 2; } } } //Excitation for (int j = 0; j < 108; j++) { try { P.DecompressedBlock[108 * i + j] = InnovationGain * Window[5 + j] + PitchGain * P.Delay[216 - Phase + 108 * i + j]; } catch (IndexOutOfRangeException) { break; } } } //Not sure about the last part of this statement... Array.Copy(P.Delay, 0, P.DecompressedBlock, 108, 324 /** sizeof(uint)*/); for (int i = 0; i < 4; i++) { for (int j = 0; j < 12; j++) P.ImpulseTrain[j] += Matrix[j]; Synthesize(P, i * 12, (uint)((i != 3) ? 1 : 33)); } }