public FlacResidual(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int order) { FlacEntropyCoding codingMethod = (FlacEntropyCoding)reader.ReadBits(FlacConstant.EntropyCodingMethodTypeLen); // 2 Bit if (codingMethod == FlacEntropyCoding.PartitionedRice || codingMethod == FlacEntropyCoding.PartitionedRice2) { int riceOrder = (int)reader.ReadBits(FlacConstant.EntropyCodingMethodPartitionedRiceOrderLen); FlacPartitionedRice rice = new FlacPartitionedRice(riceOrder, codingMethod, data.Content); if (rice.ProcessResidual(reader, header, data, order) == false) { throw new FlacException("Decoding Flac Residual failed.", FlacLayer.SubFrame); } #if DEBUG CodingMethod = codingMethod; RiceOrder = riceOrder; Rice = rice; #endif } else { throw new FlacException("Not supported RICE-Coding-Method. Stream unparseable!", FlacLayer.SubFrame); } }
public FlacResidual(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int order) { FlacEntropyCoding codingMethod = (FlacEntropyCoding)reader.ReadBits(FlacConstant.ENTROPY_CODING_METHOD_TYPE_LEN); // 2 Bit int riceOrder = -1; if (codingMethod == FlacEntropyCoding.PartitionedRice || codingMethod == FlacEntropyCoding.PartitionedRice2) { riceOrder = (int)reader.ReadBits(FlacConstant.ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN); // 4 Bit FlacPartitionedRice rice = new FlacPartitionedRice(riceOrder, codingMethod, data.Content); if (rice.ProcessResidual(reader, header, data, order) == false) { throw new FlacException("Decoding Flac Residual failed.", FlacLayer.SubFrame); } CodingMethod = codingMethod; RiceOrder = riceOrder; Rice = rice; } else { throw new FlacException("Not supported RICE-Coding-Method. Stream unparseable!", FlacLayer.SubFrame); } }
/// <summary> /// Reads and returns a single <see cref="FlacMetadata"/> from the specified <paramref name="stream"/>. /// </summary> /// <param name="stream">The stream which contains the <see cref="FlacMetadata"/>.</param> /// <returns>Returns the read <see cref="FlacMetadata"/>.</returns> /// <exception cref="FlacException">Could not read metadata.</exception> public unsafe FlacMetadata ParseMetadata(Stream stream) { bool isLastBlock; FlacMetaDataType type; int length; byte[] b = new byte[4]; if (stream.Read(b, 0, 4) <= 0) { throw new FlacException(new EndOfStreamException("Could not read metadata."), FlacLayer.Metadata); fixed(byte *headerBytes = b) { FlacBitReader bitReader = new FlacBitReader(headerBytes, 0); isLastBlock = bitReader.ReadBits(1) == 1; type = (FlacMetaDataType)bitReader.ReadBits(7); length = (int)bitReader.ReadBits(24); } long streamStartPosition = stream.Position; if (type < 0 || (int)type > 6) return(null); } var data = CreateFlacMetadataInstance(type); data.Initialize(stream, length, isLastBlock); stream.Seek(length - (stream.Position - streamStartPosition), SeekOrigin.Current); return(data); }
public FlacSubFrameConstant(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int bps) : base(header) { Value = (int)reader.ReadBits(bps); unsafe { for (int i = 0; i < header.BlockSize; i++) { int* ptr = data.destBuffer; *ptr++ = Value; } } }
public static unsafe void ProcessResidual(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int order, int partitionOrder, FlacResidualCodingMethod codingMethod) { data.Content.UpdateSize(partitionOrder); bool isRice2 = codingMethod == FlacResidualCodingMethod.PartitionedRice2; int riceParameterLength = isRice2 ? 5 : 4; int escapeCode = isRice2 ? 31 : 15; //11111 : 1111 int samplesPerPartition; int partitionCount = 1 << partitionOrder; //2^partitionOrder -> There will be 2^order partitions. -> "order" = partitionOrder in this case int *residualBuffer = data.ResidualBuffer + order; for (int p = 0; p < partitionCount; p++) { if (partitionOrder == 0) { samplesPerPartition = header.BlockSize - order; } else if (p > 0) { samplesPerPartition = header.BlockSize >> partitionOrder; } else { samplesPerPartition = (header.BlockSize >> partitionOrder) - order; } var riceParameter = reader.ReadBits(riceParameterLength); data.Content.Parameters[p] = (int)riceParameter; if (riceParameter >= escapeCode) { var raw = reader.ReadBits(5); //raw is always 5 bits (see ...(+5)) data.Content.RawBits[p] = (int)raw; for (int i = 0; i < samplesPerPartition; i++) { int sample = reader.ReadBitsSigned((int)raw); *(residualBuffer) = sample; residualBuffer++; } } else { ReadFlacRiceBlock(reader, samplesPerPartition, (int)riceParameter, residualBuffer); residualBuffer += samplesPerPartition; } } }
public FlacSubFrameConstant(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int bps) : base(header) { Value = (int)reader.ReadBits(bps); unsafe { for (int i = 0; i < header.BlockSize; i++) { int *ptr = data.destBuffer; * ptr++ = Value; } } }
public FlacSubFrameVerbatim(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int bps) : base(header) { unsafe { int *ptrDest = data.DestBuffer, ptrResidual = data.ResidualBuffer; for (int i = 0; i < header.BlockSize; i++) { int x = (int)reader.ReadBits(bps); * ptrDest++ = x; * ptrResidual++ = x; } } }
public FlacSubFrameVerbatim(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int bps) : base(header) { unsafe { int* ptrDest = data.DestBuffer, ptrResidual = data.ResidualBuffer; for (int i = 0; i < header.BlockSize; i++) { int x = (int)reader.ReadBits(bps); *ptrDest++ = x; *ptrResidual++ = x; } } }
public FlacSubFrameConstant(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int bitsPerSample) : base(header) { int value = (int)reader.ReadBits(bitsPerSample); #if FLAC_DEBUG Value = value; #endif unsafe { int* pDestinationBuffer = data.DestinationBuffer; for (int i = 0; i < header.BlockSize; i++) { *pDestinationBuffer++ = value; } } }
/// <summary> /// This method is based on the CUETools.NET BitReader (see http://sourceforge.net/p/cuetoolsnet/code/ci/default/tree/CUETools.Codecs/BitReader.cs) /// The author "Grigory Chudov" explicitly gave the permission to use the source as part of the cscore source code which got licensed under the ms-pl. /// </summary> private static unsafe void ReadFlacRiceBlock(FlacBitReader reader, int nvals, int riceParameter, int *ptrDest) { fixed(byte *putable = FlacBitReader.UnaryTable) { uint mask = (1u << riceParameter) - 1; if (riceParameter == 0) { for (int i = 0; i < nvals; i++) { *(ptrDest++) = reader.ReadUnarySigned(); } } else { for (int i = 0; i < nvals; i++) { uint bits = putable[reader.Cache >> 24]; uint msbs = bits; while (bits == 8) { reader.SeekBits(8); bits = putable[reader.Cache >> 24]; msbs += bits; } uint uval; if (riceParameter <= 16) { int btsk = riceParameter + (int)bits + 1; uval = (msbs << riceParameter) | ((reader.Cache >> (32 - btsk)) & mask); reader.SeekBits(btsk); } else { reader.SeekBits((int)(msbs & 7) + 1); uval = (msbs << riceParameter) | ((reader.Cache >> (32 - riceParameter))); reader.SeekBits(riceParameter); } *(ptrDest++) = (int)(uval >> 1 ^ -(int)(uval & 1)); } } } }
public FlacSubFrameConstant(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int bitsPerSample) : base(header) { int value = (int)reader.ReadBits(bitsPerSample); #if FLAC_DEBUG Value = value; #endif unsafe { int *pDestinationBuffer = data.DestinationBuffer; for (int i = 0; i < header.BlockSize; i++) { *pDestinationBuffer++ = value; } } }
/// <summary> /// This method is based on the CUETools.NET BitReader (see http://sourceforge.net/p/cuetoolsnet/code/ci/default/tree/CUETools.Codecs/BitReader.cs) /// The author "Grigory Chudov" explicitly gave the permission to use the source as part of the cscore source code which got licensed under the ms-pl. /// </summary> private static void ReadFlacRiceBlock(FlacBitReader reader, int nvals, int riceParameter, Span <int> ptrDest) { var putable = FlacBitReader.UnaryTable; { var mask = (1u << riceParameter) - 1; if (riceParameter == 0) { for (var i = 0; i < nvals; i++) { ptrDest[i] = reader.ReadUnarySigned(); } } else { for (var i = 0; i < nvals; i++) { uint bits = putable[reader.Cache >> 24]; var msbs = bits; while (bits == 8) { reader.SeekBits(8); bits = putable[reader.Cache >> 24]; msbs += bits; } uint uval; if (riceParameter <= 16) { var btsk = riceParameter + (int)bits + 1; uval = (msbs << riceParameter) | ((reader.Cache >> (32 - btsk)) & mask); reader.SeekBits(btsk); } else { reader.SeekBits((int)(msbs & 7) + 1); uval = (msbs << riceParameter) | ((reader.Cache >> (32 - riceParameter))); reader.SeekBits(riceParameter); } ptrDest[i] = (int)((uval >> 1) ^ -(int)(uval & 1)); } } } }
public static unsafe void ProcessResidual(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int order, int partitionOrder, FlacResidualCodingMethod codingMethod) { data.Content.UpdateSize(partitionOrder); bool isRice2 = codingMethod == FlacResidualCodingMethod.PartitionedRice2; int riceParameterLength = isRice2 ? 5 : 4; int escapeCode = isRice2 ? 31 : 15; //11111 : 1111 int samplesPerPartition; int partitionCount = 1 << partitionOrder; //2^partitionOrder -> There will be 2^order partitions. -> "order" = partitionOrder in this case int* residualBuffer = data.ResidualBuffer + order; for (int p = 0; p < partitionCount; p++) { if (partitionOrder == 0) samplesPerPartition = header.BlockSize - order; else if (p > 0) samplesPerPartition = header.BlockSize >> partitionOrder; else samplesPerPartition = (header.BlockSize >> partitionOrder) - order; var riceParameter = reader.ReadBits(riceParameterLength); data.Content.Parameters[p] = (int)riceParameter; if (riceParameter >= escapeCode) { var raw = reader.ReadBits(5); //raw is always 5 bits (see ...(+5)) data.Content.RawBits[p] = (int)raw; for (int i = 0; i < samplesPerPartition; i++) { int sample = reader.ReadBitsSigned((int)raw); *(residualBuffer) = sample; residualBuffer++; } } else { ReadFlacRiceBlock(reader, samplesPerPartition, (int)riceParameter, residualBuffer); residualBuffer += samplesPerPartition; } } }
/// <summary> /// This method is based on the CUETools.NET BitReader (see http://sourceforge.net/p/cuetoolsnet/code/ci/default/tree/CUETools.Codecs/BitReader.cs) /// The author "Grigory Chudov" explicitly gave the permission to use the source as part of the cscore source code which got licensed under the ms-pl. /// </summary> private static unsafe void ReadFlacRiceBlock(FlacBitReader reader, int nvals, int riceParameter, int* ptrDest) { fixed (byte* putable = FlacBitReader.UnaryTable) { uint mask = (1u << riceParameter) - 1; if (riceParameter == 0) { for (int i = 0; i < nvals; i++) { *(ptrDest++) = reader.ReadUnarySigned(); } } else { for (int i = 0; i < nvals; i++) { uint bits = putable[reader.Cache >> 24]; uint msbs = bits; while (bits == 8) { reader.SeekBits(8); bits = putable[reader.Cache >> 24]; msbs += bits; } uint uval; if (riceParameter <= 16) { int btsk = riceParameter + (int)bits + 1; uval = (msbs << riceParameter) | ((reader.Cache >> (32 - btsk)) & mask); reader.SeekBits(btsk); } else { reader.SeekBits((int)(msbs & 7) + 1); uval = (msbs << riceParameter) | ((reader.Cache >> (32 - riceParameter))); reader.SeekBits(riceParameter); } *(ptrDest++) = (int)(uval >> 1 ^ -(int)(uval & 1)); } } } }
public FlacResidual(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int order) { FlacResidualCodingMethod codingMethod = (FlacResidualCodingMethod)reader.ReadBits(2); // 2 Bit if (codingMethod == FlacResidualCodingMethod.PartitionedRice || codingMethod == FlacResidualCodingMethod.PartitionedRice2) { int partitionOrder = (int)reader.ReadBits(4); //"Partition order." see https://xiph.org/flac/format.html#partitioned_rice and https://xiph.org/flac/format.html#partitioned_rice2 FlacPartitionedRice.ProcessResidual(reader, header, data, order, partitionOrder, codingMethod); #if FLAC_DEBUG CodingMethodMethod = codingMethod; PartitionOrder = partitionOrder; #endif } else { throw new FlacException("Not supported RICE-Coding-Method. Stream unparseable!", FlacLayer.SubFrame); } }
private unsafe void ReadSubFrames() { var subFrames = new List<FlacSubFrameBase>(); //alocateOutput var data = AllocOuputMemory(); _subFrameData = data; var buffer = new byte[0x20000]; if ((_streamInfo.MaxFrameSize * Header.Channels * Header.BitsPerSample * 2 >> 3) > buffer.Length) { buffer = new byte[(_streamInfo.MaxFrameSize * Header.Channels * Header.BitsPerSample * 2 >> 3) - FlacConstant.FrameHeaderSize]; } var read = _stream.Read(buffer, 0, (int)Math.Min(buffer.Length, _stream.Length - _stream.Position)); fixed (byte* ptrBuffer = buffer) { var reader = new FlacBitReader(ptrBuffer, 0); for (var c = 0; c < Header.Channels; c++) { var bitsPerSample = Header.BitsPerSample; if (Header.ChannelAssignment == ChannelAssignment.MidSide || Header.ChannelAssignment == ChannelAssignment.LeftSide) bitsPerSample += c; else if (Header.ChannelAssignment == ChannelAssignment.RightSide) bitsPerSample += 1 - c; var subframe = FlacSubFrameBase.GetSubFrame(reader, data[c], Header, bitsPerSample); subFrames.Add(subframe); } reader.Flush(); //Zero-padding to byte alignment. //footer Crc16 = (short) reader.ReadBits(16); _stream.Position -= read - reader.Position; MapToChannels(_subFrameData); } }
private unsafe bool ParseHeader(ref byte *headerBuffer, FlacMetadataStreamInfo streamInfo) { const string loggerLocation = "FlacFrameHeader.ParseHeader(byte*, FlacMetadataStreamInfo)"; if (headerBuffer[0] == 0xFF && headerBuffer[1] >> 1 == 0x7C) //sync bits { if ((headerBuffer[1] & 0x02) != 0) { Error("Invalid FlacFrame. Reservedbit_0 is 1", loggerLocation); return(false); } var __headerbufferPtr = headerBuffer; var reader = new FlacBitReader(__headerbufferPtr, 0); #region blocksize //blocksize var val = headerBuffer[2] >> 4; var blocksize = -1; if (val == 0) { Error("Invalid Blocksize value: 0", loggerLocation); return(false); } if (val == 1) { blocksize = 192; } else if (val >= 2 && val <= 5) { blocksize = 576 << (val - 2); } else if (val == 6 || val == 7) { _blocksizeHint = val; } else if (val >= 8 && val <= 15) { blocksize = 256 << (val - 8); } else { Error("Invalid Blocksize value: " + val, loggerLocation); return(false); } BlockSize = blocksize; #endregion blocksize #region samplerate //samplerate val = headerBuffer[2] & 0x0F; var sampleRate = -1; if (val == 0) { if (streamInfo != null) { sampleRate = streamInfo.SampleRate; } else { Error("Missing Samplerate. Samplerate Index = 0 && streamInfoMetaData == null.", loggerLocation); return(false); } } else if (val >= 1 && val <= 11) { sampleRate = FlacConstant.SampleRateTable[val]; } else if (val >= 12 && val <= 14) { _sampleRateHint = val; } else { Error("Invalid SampleRate value: " + val, loggerLocation); return(false); } SampleRate = sampleRate; #endregion samplerate #region channels val = headerBuffer[3] >> 4; //cc: unsigned int channels; if ((val & 8) != 0) { channels = 2; if ((val & 7) > 2 || (val & 7) < 0) { Error("Invalid ChannelAssignment", loggerLocation); return(false); } ChannelAssignment = (ChannelAssignment)((val & 7) + 1); } else { channels = val + 1; ChannelAssignment = ChannelAssignment.Independent; } Channels = channels; #endregion channels #region bitspersample val = (headerBuffer[3] & 0x0E) >> 1; int bitsPerSample; if (val == 0) { if (streamInfo != null) { bitsPerSample = streamInfo.BitsPerSample; } else { Error("Missing BitsPerSample. Index = 0 && streamInfoMetaData == null.", loggerLocation); return(false); } } else if (val == 3 || val >= 7 || val < 0) { Error("Invalid BitsPerSampleIndex", loggerLocation); return(false); } else { bitsPerSample = FlacConstant.BitPerSampleTable[val]; } BitsPerSample = bitsPerSample; #endregion bitspersample if ((headerBuffer[3] & 0x01) != 0) // reserved bit -> 0 { Error("Invalid FlacFrame. Reservedbit_1 is 1", loggerLocation); return(false); } reader.ReadBits(32); //skip the first 4 bytes since they got already processed //BYTE 4 #region utf8 //variable blocksize if ((headerBuffer[1] & 0x01) != 0 || (streamInfo != null && streamInfo.MinBlockSize != streamInfo.MaxBlockSize)) { if (reader.ReadUTF8_64(out var samplenumber) && samplenumber != ulong.MaxValue) { BlockingStrategy = BlockingStrategy.VariableBlockSize; SampleNumber = (long)samplenumber; } else { Error("Invalid UTF8 Samplenumber coding.", loggerLocation); return(false); } } else //fixed blocksize { if (reader.ReadUTF8_32(out var framenumber) && framenumber != uint.MaxValue) { BlockingStrategy = BlockingStrategy.FixedBlockSize; FrameNumber = (int)framenumber; }