private unsafe List <FlacSubFrameData> AllocOuputMemory() { if (_destBuffer == null || _destBuffer.Length < (Header.Channels * Header.BlockSize)) { _destBuffer = new int[Header.Channels * Header.BlockSize]; } if (_residualBuffer == null || _residualBuffer.Length < (Header.Channels * Header.BlockSize)) { _residualBuffer = new int[Header.Channels * Header.BlockSize]; } List <FlacSubFrameData> output = new List <FlacSubFrameData>(); for (int c = 0; c < Header.Channels; c++) { fixed(int *ptrDestBuffer = _destBuffer, ptrResidualBuffer = _residualBuffer) { _handle1 = GCHandle.Alloc(_destBuffer, GCHandleType.Pinned); _handle2 = GCHandle.Alloc(_residualBuffer, GCHandleType.Pinned); FlacSubFrameData data = new FlacSubFrameData { DestinationBuffer = (ptrDestBuffer + c * Header.BlockSize), ResidualBuffer = (ptrResidualBuffer + c * Header.BlockSize) }; output.Add(data); } } return(output); }
private unsafe void RestoreSignal(FlacSubFrameData subframeData, int length, int order) { //see ftp://svr-ftp.eng.cam.ac.uk/pub/reports/auto-pdf/robinson_tr156.pdf chapter 3.2 int *residual = subframeData.ResidualBuffer + order; int *destBuffer = subframeData.DestinationBuffer + order; switch (order) { case 0: for (int i = 0; i < length; i++) { destBuffer[i] = residual[i]; } //ILUtils.MemoryCopy(data, residual, length); break; case 1: for (int i = 0; i < length; i++) { //s(t-1) destBuffer[i] = residual[i] + destBuffer[i - 1]; } break; case 2: for (int i = 0; i < length; i++) { //2s(t-1) - s(t-2) destBuffer[i] = residual[i] + 2 * destBuffer[i - 1] - destBuffer[i - 2]; } break; case 3: for (int t = 0; t < length; t++) { //3s(t-1) - 3s(t-2) + s(t-3) destBuffer[t] = residual[t] + 3 * (destBuffer[t - 1]) - 3 * (destBuffer[t - 2]) + destBuffer[t - 3]; } break; case 4: //"FLAC adds a fourth-order predictor to the zero-to-third-order predictors used by Shorten." (see https://xiph.org/flac/format.html#prediction) for (int t = 0; t < length; t++) { destBuffer[t] = residual[t] + 4 * destBuffer[t - 1] - 6 * destBuffer[t - 2] + 4 * destBuffer[t - 3] - destBuffer[t - 4]; } break; default: Debug.WriteLine("Invalid FlacFixedSubFrame predictororder."); return; } }
public unsafe FlacSubFrameFixed(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int bitsPerSample, int order) : base(header) { for (int i = 0; i < order; i++) //order = predictor order { data.ResidualBuffer[i] = data.DestinationBuffer[i] = reader.ReadBitsSigned(bitsPerSample); } var residual = new FlacResidual(reader, header, data, order); //necessary for decoding RestoreSignal(data, header.BlockSize - order, order); #if FLAC_DEBUG Residual = residual; #endif }
public unsafe static FlacSubFrameBase GetSubFrame(FlacBitReader reader, FlacSubFrameData data, FlacFrameHeader header, int bitsPerSample) { int wastedBits = 0, order; uint firstByte = reader.ReadBits(8); if ((firstByte & 0x80) != 0) //Zero bit padding, to prevent sync-fooling string of 1s { Debug.WriteLine("Flacdecoder subframe-header got no zero-bit padding."); return(null); } bool hasWastedBits = (firstByte & 1) != 0; //Wasted bits-per-sample' flag if (hasWastedBits) { int k = (int)reader.ReadUnary(); wastedBits = k + 1; //"k-1" follows -> add 1 bitsPerSample -= wastedBits; } FlacSubFrameBase subFrame; var subframeType = (firstByte & 0x7E) >> 1; //0111 1110 if (subframeType == 0) //000000 { subFrame = new FlacSubFrameConstant(reader, header, data, bitsPerSample); } else if (subframeType == 1) //000001 { subFrame = new FlacSubFrameVerbatim(reader, header, data, bitsPerSample); } else if ((subframeType & 0x20) != 0) //100000 = 0x20 { order = (int)(subframeType & 0x1F) + 1; subFrame = new FlacSubFrameLPC(reader, header, data, bitsPerSample, order); } else if ((subframeType & 0x08) != 0) //001000 = 0x08 { order = (int)(subframeType & 0x07); if (order > 4) { return(null); } subFrame = new FlacSubFrameFixed(reader, header, data, bitsPerSample, order); } else { Debug.WriteLine(String.Format("Invalid Flac-SubframeType. SubframeType: 0x{0:x}.", subframeType)); return(null); } if (hasWastedBits) { int *destination = data.DestinationBuffer; for (int i = 0; i < header.BlockSize; i++) { *(destination++) <<= wastedBits; } } #if FLAC_DEBUG subFrame.WastedBits = wastedBits; #endif return(subFrame); }
public unsafe FlacSubFrameLPC(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int bitsPerSample, int order) : base(header) { var warmup = new int[order]; for (int i = 0; i < order; i++) { warmup[i] = data.ResidualBuffer[i] = reader.ReadBitsSigned(bitsPerSample); } int coefPrecision = (int)reader.ReadBits(4); if (coefPrecision == 0x0F) { throw new FlacException("Invalid \"quantized linear predictor coefficients' precision in bits\" was invalid. Must not be 0x0F.", FlacLayer.SubFrame); } coefPrecision += 1; int shiftNeeded = reader.ReadBitsSigned(5); if (shiftNeeded < 0) { throw new FlacException("'\"Quantized linear predictor coefficient shift needed in bits\" was negative.", FlacLayer.SubFrame); } var q = new int[order]; for (int i = 0; i < order; i++) { q[i] = reader.ReadBitsSigned(coefPrecision); } //decode the residual var residual = new FlacResidual(reader, header, data, order); for (int i = 0; i < order; i++) { data.DestinationBuffer[i] = data.ResidualBuffer[i]; } int *residualBuffer0 = data.ResidualBuffer + order; int *destinationBuffer0 = data.DestinationBuffer + order; int blockSizeToProcess = header.BlockSize - order; if (bitsPerSample + coefPrecision + Log2(order) <= 32) { RestoreLPCSignal32(residualBuffer0, destinationBuffer0, blockSizeToProcess, order, q, shiftNeeded); } else { RestoreLPCSignal64(residualBuffer0, destinationBuffer0, blockSizeToProcess, order, q, shiftNeeded); } #if FLAC_DEBUG QLPCoeffPrecision = coefPrecision; LPCShiftNeeded = shiftNeeded; Warmup = warmup; Residual = residual; QLPCoeffs = q; #endif }