unsafe void restore_samples_fixed(FlacFrame frame, int ch) { FlacSubframeInfo sub = frame.subframes[ch]; AudioSamples.MemCpy(sub.samples, sub.best.residual, sub.best.order); int *data = sub.samples + sub.best.order; int *residual = sub.best.residual + sub.best.order; int data_len = frame.blocksize - sub.best.order; int s0, s1, s2; switch (sub.best.order) { case 0: AudioSamples.MemCpy(data, residual, data_len); break; case 1: s1 = data[-1]; for (int i = data_len; i > 0; i--) { s1 += *(residual++); *(data++) = s1; } //data[i] = residual[i] + data[i - 1]; break; case 2: s2 = data[-2]; s1 = data[-1]; for (int i = data_len; i > 0; i--) { s0 = *(residual++) + (s1 << 1) - s2; *(data++) = s0; s2 = s1; s1 = s0; } //data[i] = residual[i] + data[i - 1] * 2 - data[i - 2]; break; case 3: for (int i = 0; i < data_len; i++) { data[i] = residual[i] + (((data[i - 1] - data[i - 2]) << 1) + (data[i - 1] - data[i - 2])) + data[i - 3]; } break; case 4: for (int i = 0; i < data_len; i++) { data[i] = residual[i] + ((data[i - 1] + data[i - 3]) << 2) - ((data[i - 2] << 2) + (data[i - 2] << 1)) - data[i - 4]; } break; } }
unsafe void decode_subframe_fixed(BitReader bitreader, FlacFrame frame, int ch) { // warm-up samples int obits = frame.subframes[ch].obits; for (int i = 0; i < frame.subframes[ch].best.order; i++) { frame.subframes[ch].best.residual[i] = bitreader.readbits_signed(obits); } // residual decode_residual(bitreader, frame, ch); }
unsafe void decode_residual(BitReader bitreader, FlacFrame frame, int ch) { // rice-encoded block // coding method frame.subframes[ch].best.rc.coding_method = (int)bitreader.readbits(2); // ????? == 0 if (frame.subframes[ch].best.rc.coding_method != 0 && frame.subframes[ch].best.rc.coding_method != 1) { throw new Exception("unsupported residual coding"); } // partition order frame.subframes[ch].best.rc.porder = (int)bitreader.readbits(4); if (frame.subframes[ch].best.rc.porder > 8) { throw new Exception("invalid partition order"); } int psize = frame.blocksize >> frame.subframes[ch].best.rc.porder; int res_cnt = psize - frame.subframes[ch].best.order; int rice_len = 4 + frame.subframes[ch].best.rc.coding_method; // residual int j = frame.subframes[ch].best.order; int *r = frame.subframes[ch].best.residual + j; for (int p = 0; p < (1 << frame.subframes[ch].best.rc.porder); p++) { if (p == 1) { res_cnt = psize; } int n = Math.Min(res_cnt, frame.blocksize - j); int k = frame.subframes[ch].best.rc.rparams[p] = (int)bitreader.readbits(rice_len); if (k == (1 << rice_len) - 1) { k = frame.subframes[ch].best.rc.esc_bps[p] = (int)bitreader.readbits(5); for (int i = n; i > 0; i--) { *(r++) = bitreader.readbits_signed((int)k); } } else { bitreader.read_rice_block(n, (int)k, r); r += n; } j += n; } }
unsafe void restore_samples_lpc(FlacFrame frame, int ch) { FlacSubframeInfo sub = frame.subframes[ch]; ulong csum = 0; fixed(int *coefs = sub.best.coefs) { for (int i = sub.best.order; i > 0; i--) { csum += (ulong)Math.Abs(coefs[i - 1]); } if ((csum << sub.obits) >= 1UL << 32) { lpc.decode_residual_long(sub.best.residual, sub.samples, frame.blocksize, sub.best.order, coefs, sub.best.shift); } else { lpc.decode_residual(sub.best.residual, sub.samples, frame.blocksize, sub.best.order, coefs, sub.best.shift); } } }
public AudioDecoder(DecoderSettings settings, string path, Stream IO = null) { m_settings = settings; _path = path; _IO = IO != null ? IO : new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000); crc8 = new Crc8(); _framesBuffer = new byte[0x20000]; decode_metadata(); frame = new FlacFrame(PCM.ChannelCount); framereader = new BitReader(); //max_frame_size = 16 + ((Flake.MAX_BLOCKSIZE * PCM.BitsPerSample * PCM.ChannelCount + 1) + 7) >> 3); if (((int)max_frame_size * PCM.BitsPerSample * PCM.ChannelCount * 2 >> 3) > _framesBuffer.Length) { byte[] temp = _framesBuffer; _framesBuffer = new byte[((int)max_frame_size * PCM.BitsPerSample * PCM.ChannelCount * 2 >> 3)]; if (_framesBufferLength > 0) { Array.Copy(temp, _framesBufferOffset, _framesBuffer, 0, _framesBufferLength); } _framesBufferOffset = 0; } _samplesInBuffer = 0; if (PCM.BitsPerSample != 16 && PCM.BitsPerSample != 24) { throw new Exception("invalid flac file"); } samplesBuffer = new int[FlakeConstants.MAX_BLOCKSIZE * PCM.ChannelCount]; residualBuffer = new int[FlakeConstants.MAX_BLOCKSIZE * PCM.ChannelCount]; }
unsafe void restore_samples(FlacFrame frame) { for (int ch = 0; ch < PCM.ChannelCount; ch++) { switch (frame.subframes[ch].best.type) { case SubframeType.Constant: AudioSamples.MemSet(frame.subframes[ch].samples, frame.subframes[ch].best.residual[0], frame.blocksize); break; case SubframeType.Verbatim: AudioSamples.MemCpy(frame.subframes[ch].samples, frame.subframes[ch].best.residual, frame.blocksize); break; case SubframeType.Fixed: restore_samples_fixed(frame, ch); break; case SubframeType.LPC: restore_samples_lpc(frame, ch); break; } if (frame.subframes[ch].wbits != 0) { int *s = frame.subframes[ch].samples; int x = (int)frame.subframes[ch].wbits; for (int i = frame.blocksize; i > 0; i--) { *(s++) <<= x; } } } if (frame.ch_mode != ChannelMode.NotStereo) { int *l = frame.subframes[0].samples; int *r = frame.subframes[1].samples; switch (frame.ch_mode) { case ChannelMode.LeftRight: break; case ChannelMode.MidSide: for (int i = frame.blocksize; i > 0; i--) { int mid = *l; int side = *r; mid <<= 1; mid |= (side & 1); /* i.e. if 'side' is odd... */ *(l++) = (mid + side) >> 1; *(r++) = (mid - side) >> 1; } break; case ChannelMode.LeftSide: for (int i = frame.blocksize; i > 0; i--) { int _l = *(l++), _r = *r; *(r++) = _l - _r; } break; case ChannelMode.RightSide: for (int i = frame.blocksize; i > 0; i--) { *(l++) += *(r++); } break; } } }
unsafe void decode_subframes(BitReader bitreader, FlacFrame frame) { fixed(int *r = residualBuffer, s = samplesBuffer) for (int ch = 0; ch < PCM.ChannelCount; ch++) { // subframe header uint t1 = bitreader.readbit(); // ?????? == 0 if (t1 != 0) { throw new Exception("unsupported subframe coding (ch == " + ch.ToString() + ")"); } int type_code = (int)bitreader.readbits(6); frame.subframes[ch].wbits = (int)bitreader.readbit(); if (frame.subframes[ch].wbits != 0) { frame.subframes[ch].wbits += (int)bitreader.read_unary(); } frame.subframes[ch].obits = PCM.BitsPerSample - frame.subframes[ch].wbits; switch (frame.ch_mode) { case ChannelMode.MidSide: frame.subframes[ch].obits += ch; break; case ChannelMode.LeftSide: frame.subframes[ch].obits += ch; break; case ChannelMode.RightSide: frame.subframes[ch].obits += 1 - ch; break; } frame.subframes[ch].best.type = (SubframeType)type_code; frame.subframes[ch].best.order = 0; if ((type_code & (uint)SubframeType.LPC) != 0) { frame.subframes[ch].best.order = (type_code - (int)SubframeType.LPC) + 1; frame.subframes[ch].best.type = SubframeType.LPC; } else if ((type_code & (uint)SubframeType.Fixed) != 0) { frame.subframes[ch].best.order = (type_code - (int)SubframeType.Fixed); frame.subframes[ch].best.type = SubframeType.Fixed; } frame.subframes[ch].best.residual = r + ch * FlakeConstants.MAX_BLOCKSIZE; frame.subframes[ch].samples = s + ch * FlakeConstants.MAX_BLOCKSIZE; // subframe switch (frame.subframes[ch].best.type) { case SubframeType.Constant: decode_subframe_constant(bitreader, frame, ch); break; case SubframeType.Verbatim: decode_subframe_verbatim(bitreader, frame, ch); break; case SubframeType.Fixed: decode_subframe_fixed(bitreader, frame, ch); break; case SubframeType.LPC: decode_subframe_lpc(bitreader, frame, ch); break; default: throw new Exception("invalid subframe type"); } } }
unsafe void decode_subframe_constant(BitReader bitreader, FlacFrame frame, int ch) { int obits = frame.subframes[ch].obits; frame.subframes[ch].best.residual[0] = bitreader.readbits_signed(obits); }
unsafe void decode_frame_header(BitReader bitreader, FlacFrame frame) { int header_start = bitreader.Position; if (bitreader.readbits(15) != 0x7FFC) { throw new Exception("invalid frame"); } uint vbs = bitreader.readbit(); frame.bs_code0 = (int)bitreader.readbits(4); uint sr_code0 = bitreader.readbits(4); frame.ch_mode = (ChannelMode)bitreader.readbits(4); uint bps_code = bitreader.readbits(3); if (FlakeConstants.flac_bitdepths[bps_code] != PCM.BitsPerSample) { throw new Exception("unsupported bps coding"); } uint t1 = bitreader.readbit(); // == 0????? if (t1 != 0) { throw new Exception("unsupported frame coding"); } frame.frame_number = (int)bitreader.read_utf8(); // custom block size if (frame.bs_code0 == 6) { frame.bs_code1 = (int)bitreader.readbits(8); frame.blocksize = frame.bs_code1 + 1; } else if (frame.bs_code0 == 7) { frame.bs_code1 = (int)bitreader.readbits(16); frame.blocksize = frame.bs_code1 + 1; } else { frame.blocksize = FlakeConstants.flac_blocksizes[frame.bs_code0]; } // custom sample rate if (sr_code0 < 1 || sr_code0 > 11) { // sr_code0 == 12 -> sr == bitreader.readbits(8) * 1000; // sr_code0 == 13 -> sr == bitreader.readbits(16); // sr_code0 == 14 -> sr == bitreader.readbits(16) * 10; throw new Exception("invalid sample rate mode"); } int frame_channels = (int)frame.ch_mode + 1; if (frame_channels > 11) { throw new Exception("invalid channel mode"); } if (frame_channels == 2 || frame_channels > 8) // Mid/Left/Right Side Stereo { frame_channels = 2; } else { frame.ch_mode = ChannelMode.NotStereo; } if (frame_channels != PCM.ChannelCount) { throw new Exception("invalid channel mode"); } // CRC-8 of frame header byte crc = do_crc ? crc8.ComputeChecksum(bitreader.Buffer, header_start, bitreader.Position - header_start) : (byte)0; frame.crc8 = (byte)bitreader.readbits(8); if (do_crc && frame.crc8 != crc) { throw new Exception("header crc mismatch"); } }