public static Celt FromStream(Stream stream) { Celt celt = new Celt(); using (AwesomeReader ar = new AwesomeReader(stream, false)) { // Checks for "BFAD" magic switch (ar.ReadInt32()) { case MAGIC: ar.BigEndian = false; break; case MAGIC_R: ar.BigEndian = true; break; default: throw new Exception("Invalid magic. Expected \"BFAD\""); } celt.BigEndian = ar.BigEndian; // Sets endianess // Parses header information celt.Channels = ar.ReadUInt16(); celt.Encrypted = Convert.ToBoolean(ar.ReadInt16()); celt.TotalSamples = ar.ReadUInt32(); celt.Bitrate = ar.ReadUInt32(); celt.FrameSize = ar.ReadUInt16(); celt.Unknown1 = ar.ReadUInt16(); celt.SampleRate = ar.ReadUInt16(); celt.Unknown2 = ar.ReadUInt16(); celt.ReckoningOffset = ar.ReadUInt32(); celt.ReckoningSize = ar.ReadUInt32(); celt.PacketStreamOffset = ar.ReadUInt32(); celt.PacketStreamSize = ar.ReadUInt32(); celt.FixOffsets(); // Only useful for audio extracted from RAM, harmless uint reckonSize = celt.PacketStreamOffset - celt.ReckoningOffset; // Multiple of 4 uint streamSize = celt.PacketStreamSize; if ((reckonSize + streamSize) % 16 != 0) { streamSize += 16 - ((reckonSize + streamSize) % 16); } if (celt.Encrypted) { var encryptedBytes = ar.ReadBytes((int)(reckonSize + streamSize)); // Decrypt audio data in ECB mode with the 256-bit key using (Aes aes = Aes.Create()) { aes.Mode = CipherMode.ECB; aes.KeySize = 256; aes.BlockSize = 128; aes.Padding = PaddingMode.None; using (var decryptor = aes.CreateDecryptor(AesKey, new byte[16])) { decryptor.TransformBlock(encryptedBytes, 0, encryptedBytes.Length, encryptedBytes, 0); } } celt.Reckoning = new byte[reckonSize]; celt.PacketStream = new byte[streamSize]; Array.Copy(encryptedBytes, celt.Reckoning, reckonSize); Array.Copy(encryptedBytes, reckonSize, celt.PacketStream, 0, streamSize); celt.Encrypted = false; } else { celt.Reckoning = ar.ReadBytes((int)reckonSize); celt.PacketStream = ar.ReadBytes((int)streamSize); } } return(celt); }
public static Celt FromAudio(string path) { // TODO: Clean all of this up and implement tracking packet offsets AudioFileReader afr = new AudioFileReader(path); Celt celt = new Celt() { SampleRate = (ushort)afr.WaveFormat.SampleRate }; OpusEncoder encoder = OpusEncoder.Create(celt.SampleRate, NUM_CHANNELS, OpusApplication.OPUS_APPLICATION_AUDIO); encoder.Bitrate = (int)celt.Bitrate; encoder.ForceMode = OpusMode.MODE_CELT_ONLY; encoder.SignalType = OpusSignal.OPUS_SIGNAL_MUSIC; float[] buffer = new float[celt.FrameSize * NUM_CHANNELS]; byte[] packet = new byte[MAX_PACKET_SIZE]; byte[] packetSize = new byte[2]; bool skipMode = true; List <int> recks = new List <int>() { 0 }; MemoryStream ms = new MemoryStream(); // Encoding loop while (afr.Position < afr.Length) { int bufferLength = afr.Read(buffer, 0, buffer.Length); int packetLength = encoder.Encode(buffer, 0, celt.FrameSize, packet, 0, packet.Length); // Tracks reckoning counts if (packetLength <= 3) // Checks if packet is empty { if (!skipMode) { recks.Add(0); skipMode = !skipMode; } recks[recks.Count - 1] += 1; continue; } else { if (skipMode) { recks.Add(0); skipMode = !skipMode; } recks[recks.Count - 1] += 1; } // Encodes 15-bit packet size packetSize[0] = (byte)(0x80 | (0xFF & (packetLength >> 8))); packetSize[1] = (byte)(0xFF & packetLength); ms.Write(packetSize, 0, packetSize.Length); ms.Write(packet, 0, packetLength); } int packetCount = recks.Sum(); int hdEncodeSize; byte[] hdBytes; // Writes packet offsets using (MemoryStream hdStream = new MemoryStream()) { byte[] hdBuff = new byte[2]; foreach (int count in recks) { if (count > 127) { // Encodes as two bytes hdBuff[0] = (byte)(0x80 | (0xFF & (count >> 8))); hdBuff[1] = (byte)(0xFF & count); hdStream.Write(hdBuff, 0, 2); } else { // Encodes as one byte hdBuff[0] = (byte)count; hdStream.Write(hdBuff, 0, 1); } } hdEncodeSize = (int)hdStream.Length; // Adds remaining bytes if (hdEncodeSize % 4 != 0) { int difference = 4 - (hdEncodeSize % 4); hdStream.Write(new byte[difference], 0, difference); } hdBytes = hdStream.ToArray(); } celt.TotalSamples = (uint)(packetCount * celt.FrameSize); celt.Reckoning = hdBytes; celt.ReckoningOffset = 40; celt.ReckoningSize = (uint)hdEncodeSize; celt.PacketStreamOffset = (uint)(40 + hdBytes.Length); celt.PacketStreamSize = (uint)ms.Length; // Adds remaining bytes if ((ms.Length + hdBytes.Length) % 16 != 0) { int difference = 16 - ((int)(ms.Length + hdBytes.Length) % 16); ms.Write(new byte[difference], 0, difference); } celt.PacketStream = ms.ToArray(); return(celt); }