private void ReadFrame() { const int FrameHeaderLength = 2 + 1 + 1; const int FrameSync = 0xFFF8; const int FrameSyncMask = 0xFFFC; const int ReservedBlockSizeSamplesType = 0; const int InvalidSampleRateType = 15; int read; byte[] data = new byte[FrameHeaderLength]; if (recordType != FlacRecordType.Sync) { read = BaseStream.Read(data, 0, FrameHeaderLength); if (read < FrameHeaderLength) { if (read <= 0) { recordType = FlacRecordType.Eof; return; } throw new FlacException("Unexpected eof of stream: invalid frame header length"); } if (((data[0] << 8 | data[1]) & FrameSyncMask) != FrameSync) { throw new FlacException("Frame sync is expected"); } } else { const int SyncReadLength = 2; read = BaseStream.Read(data, SyncReadLength, FrameHeaderLength - SyncReadLength); if (read + SyncReadLength < FrameHeaderLength) { throw new FlacException("Unexpected eof of stream: invalid frame header length"); } data[0] = (byte)(FrameSync >> 8); data[1] = secondSyncByte; } if ((data[1] & 0x02) != 0) { throw new FlacException("Frame header reserved bit (15) shall not be 1"); } this.variableBlockSize = (data[1] & 0x01) != 0; int blockSizeSamplesType = data[2] >> 4; if (blockSizeSamplesType == ReservedBlockSizeSamplesType) { throw new FlacException("Frame header block size samples shall not be set to reserved"); } int previousBlockSize = this.blockSize; this.blockSize = FlacCommons.StaticBlockSizeSamples[blockSizeSamplesType]; int sampleRateType = data[2] & 0x0F; if (sampleRateType == InvalidSampleRateType) { throw new FlacException("Frame header sample rate type is invalid"); } this.sampleRate = FlacCommons.StaticSampleRates[sampleRateType]; int channelAssignmentType = data[3] >> 4; if (channelAssignmentType >= FlacCommons.StaticChannelAssignments.Length) { throw new FlacException("Frame header channel assignments are defined as reserved"); } this.channelAssignmentType = (SoundChannelAssignmentType)channelAssignmentType; this.channelAssignment = FlacCommons.StaticChannelAssignments[channelAssignmentType]; if (channelAssignment == null) { throw new FlacException("Frame header channel assignment are not defined"); } this.channelCount = channelAssignment.Length; int sampleSizeInBitsType = (data[3] >> 1) & 0x07; if (sampleSizeInBitsType == FlacCommons.StreaminfoSizeInBitsType) { this.sampleSizeInBits = Streaminfo.BitsPerSample; } else if (FlacCommons.StaticSampleSizeInBits[sampleSizeInBitsType] > 0) { this.sampleSizeInBits = FlacCommons.StaticSampleSizeInBits[sampleSizeInBitsType]; } else { throw new FlacException("Frame header sample size is defined as reserved"); } if ((data[3] & 1) != 0) { throw new FlacException("Frame header reserved bit (31) shall not be 1"); } MemoryStream ms = new MemoryStream(20); ms.Write(data, 0, FrameHeaderLength); byte[] numberData; if (variableBlockSize) { ReadUtf8Number(out this.sampleNumber, out numberData); if (numberData.Length > 7) { throw new FlacException("Invalid variable block size"); } } else { ReadUtf8Number(out this.frameNumber, out numberData); if (numberData.Length > 6) { throw new FlacException("Invalid frame number"); } this.sampleNumber = this.frameNumber == 0 ? 0 : previousBlockSize *this.frameNumber; } ms.Write(numberData, 0, numberData.Length); byte[] blockSizeData = null; switch (blockSizeSamplesType) { case FlacCommons.Bit8BlockSizeSamplesType: blockSizeData = ReadExactly(1); this.blockSize = (int)blockSizeData[0] + 1; break; case FlacCommons.Bit16BlockSizeSamplesType: blockSizeData = ReadExactly(2); this.blockSize = (blockSizeData[0] << 8 | blockSizeData[1]) + 1; break; } if (blockSizeData != null) { ms.Write(blockSizeData, 0, blockSizeData.Length); } byte[] sampleRateData = null; switch (sampleRateType) { case FlacCommons.StreaminfoSampleRateType: this.sampleRate = Streaminfo.SampleRate; break; case FlacCommons.Bit8SampleRateType: sampleRateData = ReadExactly(1); this.sampleRate = sampleRateData[0]; break; case FlacCommons.Bit16SampleRateType: sampleRateData = ReadExactly(2); this.sampleRate = sampleRateData[0] << 8 | sampleRateData[1]; break; case FlacCommons.Bit16Mult10SampleRateType: sampleRateData = ReadExactly(2); this.sampleRate = (sampleRateData[0] << 8 | sampleRateData[1]) * 10; break; } if (sampleRateData != null) { ms.Write(sampleRateData, 0, sampleRateData.Length); } byte[] readData = ms.ToArray(); byte crc8 = CrcUtils.Crc8(0, readData); int headerCrc8 = BaseStream.ReadByte(); if (headerCrc8 < 0) { throw new FlacException("Unexpected end of stream: frame CRC8 expected"); } else if (crc8 != headerCrc8) { throw new FlacException("Invalid frame CRC"); } ushort currentCrc16 = CrcUtils.Crc16( CrcUtils.Crc16(0, readData), (byte)headerCrc8); bitReader = new FlacBitStreamReader(BaseStream, currentCrc16); lastFrameHeaderData = new byte[readData.Length + 1]; Array.Copy(readData, lastFrameHeaderData, readData.Length); lastFrameHeaderData[readData.Length] = crc8; recordType = FlacRecordType.Frame; }
public void WriteFrame(FlacMethodAndDataPair[] methods, SoundChannelAssignmentType channelAssignment) { EnsureFramesMode(); sink.StartFrame(streamPosition, currentSample); if (methods == null) { throw new ArgumentNullException("methods"); } if (methods.Length != Streaminfo.ChannelsCount) { throw new ArgumentNullException("Methods items does not correspond to amount of channels"); } int samplesCount = methods[0].Data.Length; const byte Blocking = 0x00; // fixed MemoryStream frameHeader = new MemoryStream(); // sync code + reserved = 0 + blocking frameHeader.WriteByte(0xFF); frameHeader.WriteByte(0xF8 | Blocking); int interChannelSamplesTypeIndex = Array.IndexOf(FlacCommons.StaticBlockSizeSamples, samplesCount); int interChannelSamplesType; if (interChannelSamplesTypeIndex > 0) { interChannelSamplesType = interChannelSamplesTypeIndex; } else if (samplesCount > 256) { interChannelSamplesType = FlacCommons.Bit16BlockSizeSamplesType; } else { interChannelSamplesType = FlacCommons.Bit8BlockSizeSamplesType; } int sampleRateTypeIndex = Array.IndexOf(FlacCommons.StaticSampleRates, Streaminfo.SampleRate); int sampleRateType = sampleRateTypeIndex > 0 ? sampleRateTypeIndex : FlacCommons.StreaminfoSampleRateType; frameHeader.WriteByte((byte)(interChannelSamplesType << 4 | sampleRateType)); int channelAssignmetType = (int)channelAssignment; int sampleSizeInBitsTypeIndex = Array.IndexOf(FlacCommons.StaticSampleSizeInBits, Streaminfo.BitsPerSample); int sampleSizeInBitsType = sampleSizeInBitsTypeIndex > 0 ? sampleSizeInBitsTypeIndex : FlacCommons.StreaminfoSizeInBitsType; frameHeader.WriteByte((byte)(channelAssignmetType << 4 | sampleSizeInBitsType << 1)); WriteUtf8Number(frameHeader, frameNumber); switch (interChannelSamplesType) { case FlacCommons.Bit8BlockSizeSamplesType: frameHeader.WriteByte((byte)(samplesCount - 1)); break; case FlacCommons.Bit16BlockSizeSamplesType: frameHeader.WriteByte((byte)((samplesCount - 1) >> 8)); frameHeader.WriteByte((byte)(samplesCount - 1)); break; } frameHeader.Dispose(); byte[] frameHeaderData = frameHeader.ToArray(); byte crc8 = CrcUtils.Crc8(0, frameHeaderData); BaseStream.Write(frameHeaderData, 0, frameHeaderData.Length); BaseStream.WriteByte(crc8); ++frameNumber; ushort crc16Seed = CrcUtils.Crc16(CrcUtils.Crc16(0, frameHeaderData), crc8); // write channels FlacBitStreamWriter bitWriter = new FlacBitStreamWriter(BaseStream, crc16Seed); for (int i = 0; i < methods.Length; i++) { WriteSubframe(bitWriter, methods[i]); } int subframesLength; ushort crc16; bitWriter.Complete(out crc16, out subframesLength); // write footer BaseStream.WriteByte((byte)(crc16 >> 8)); BaseStream.WriteByte((byte)crc16); int frameSize = frameHeaderData.Length + 1 + subframesLength + 2; streamPosition += frameSize; currentSample += samplesCount; sink.EndFrame(streamPosition, currentSample); }
public void WriteFrame(int[][] samples, SoundChannelAssignmentType channelAssigment) { if (samples == null) { throw new ArgumentNullException("samples"); } int channelsCount = Streaminfo.ChannelsCount; if (samples.Length != channelsCount) { throw new ArgumentException("Expected same amount of channels as in Streaminfo"); } int samplesPerChannel = samples[0].Length; if ( // samplesPerChannel < Streaminfo.MinBlockSize || Streaminfo.MaxBlockSize < samplesPerChannel) { throw new ArgumentException("Amount of samples more or less than specified in Streaminfo"); } for (int i = 1; i < channelsCount; i++) { if (samplesPerChannel != samples[i].Length) { throw new ArgumentException("Expected same amount of samples on all the channels"); } } FlacMethod[] methods; if (channelsCount == 2 && channelAssigment == SoundChannelAssignmentType.Auto) { FlacMethodAndDataPair[] methodsForLeftAndRight; SoundChannelAssignmentType assigmentType = FindBestMethod(samples[0], samples[1], out methodsForLeftAndRight); WriteFrame(methodsForLeftAndRight, assigmentType); } else { methods = new FlacMethod[channelsCount]; SoundChannelAssignment[] assignments; SoundChannelAssignmentType definedChannelAssigmentType; if (channelAssigment == SoundChannelAssignmentType.Auto) { assignments = FlacCommons.StaticChannelAssignments[channelsCount - 1]; definedChannelAssigmentType = (SoundChannelAssignmentType)(channelsCount - 1); } else { assignments = FlacCommons.StaticChannelAssignments[(int)channelAssigment]; definedChannelAssigmentType = channelAssigment; } FlacMethodAndDataPair[] samplesAndMethods = estimator.FindBestMethods( samples, Streaminfo.BitsPerSample); WriteFrame(samplesAndMethods, definedChannelAssigmentType); } }
private void ReadFrame() { const int FrameHeaderLength = 2 + 1 + 1; const int FrameSync = 0xFFF8; const int FrameSyncMask = 0xFFFC; const int ReservedBlockSizeSamplesType = 0; const int InvalidSampleRateType = 15; int read; byte[] data = new byte[FrameHeaderLength]; if (recordType != FlacRecordType.Sync) { read = BaseStream.Read(data, 0, FrameHeaderLength); if (read < FrameHeaderLength) { if (read <= 0) { recordType = FlacRecordType.Eof; return; } throw new FlacException("Unexpected eof of stream: invalid frame header length"); } if (((data[0] << 8 | data[1]) & FrameSyncMask) != FrameSync) throw new FlacException("Frame sync is expected"); } else { const int SyncReadLength = 2; read = BaseStream.Read(data, SyncReadLength, FrameHeaderLength - SyncReadLength); if(read + SyncReadLength < FrameHeaderLength) throw new FlacException("Unexpected eof of stream: invalid frame header length"); data[0] = (byte)(FrameSync >> 8); data[1] = secondSyncByte; } if((data[1] & 0x02) != 0) throw new FlacException("Frame header reserved bit (15) shall not be 1"); this.variableBlockSize = (data[1] & 0x01) != 0; int blockSizeSamplesType = data[2] >> 4; if(blockSizeSamplesType == ReservedBlockSizeSamplesType) throw new FlacException("Frame header block size samples shall not be set to reserved"); int previousBlockSize = this.blockSize; this.blockSize = FlacCommons.StaticBlockSizeSamples[blockSizeSamplesType]; int sampleRateType = data[2] & 0x0F; if(sampleRateType == InvalidSampleRateType) throw new FlacException("Frame header sample rate type is invalid"); this.sampleRate = FlacCommons.StaticSampleRates[sampleRateType]; int channelAssignmentType = data[3] >> 4; if (channelAssignmentType >= FlacCommons.StaticChannelAssignments.Length) throw new FlacException("Frame header channel assignments are defined as reserved"); this.channelAssignmentType = (SoundChannelAssignmentType)channelAssignmentType; this.channelAssignment = FlacCommons.StaticChannelAssignments[channelAssignmentType]; if (channelAssignment == null) throw new FlacException("Frame header channel assignment are not defined"); this.channelCount = channelAssignment.Length; int sampleSizeInBitsType = (data[3] >> 1) & 0x07; if (sampleSizeInBitsType == FlacCommons.StreaminfoSizeInBitsType) this.sampleSizeInBits = Streaminfo.BitsPerSample; else if (FlacCommons.StaticSampleSizeInBits[sampleSizeInBitsType] > 0) this.sampleSizeInBits = FlacCommons.StaticSampleSizeInBits[sampleSizeInBitsType]; else throw new FlacException("Frame header sample size is defined as reserved"); if((data[3] & 1) != 0) throw new FlacException("Frame header reserved bit (31) shall not be 1"); MemoryStream ms = new MemoryStream(20); ms.Write(data, 0, FrameHeaderLength); byte[] numberData; if (variableBlockSize) { ReadUtf8Number(out this.sampleNumber, out numberData); if (numberData.Length > 7) throw new FlacException("Invalid variable block size"); } else { ReadUtf8Number(out this.frameNumber, out numberData); if (numberData.Length > 6) throw new FlacException("Invalid frame number"); this.sampleNumber = this.frameNumber == 0 ? 0 : previousBlockSize * this.frameNumber; } ms.Write(numberData, 0, numberData.Length); byte[] blockSizeData = null; switch (blockSizeSamplesType) { case FlacCommons.Bit8BlockSizeSamplesType: blockSizeData = ReadExactly(1); this.blockSize = (int)blockSizeData[0] + 1; break; case FlacCommons.Bit16BlockSizeSamplesType: blockSizeData = ReadExactly(2); this.blockSize = (blockSizeData[0] << 8 | blockSizeData[1]) + 1; break; } if(blockSizeData != null) ms.Write(blockSizeData, 0, blockSizeData.Length); byte[] sampleRateData = null; switch (sampleRateType) { case FlacCommons.StreaminfoSampleRateType: this.sampleRate = Streaminfo.SampleRate; break; case FlacCommons.Bit8SampleRateType: sampleRateData = ReadExactly(1); this.sampleRate = sampleRateData[0]; break; case FlacCommons.Bit16SampleRateType: sampleRateData = ReadExactly(2); this.sampleRate = sampleRateData[0] << 8 | sampleRateData[1]; break; case FlacCommons.Bit16Mult10SampleRateType: sampleRateData = ReadExactly(2); this.sampleRate = (sampleRateData[0] << 8 | sampleRateData[1]) * 10; break; } if (sampleRateData != null) ms.Write(sampleRateData, 0, sampleRateData.Length); byte[] readData = ms.ToArray(); byte crc8 = CrcUtils.Crc8(0, readData); int headerCrc8 = BaseStream.ReadByte(); if (headerCrc8 < 0) throw new FlacException("Unexpected end of stream: frame CRC8 expected"); else if(crc8 != headerCrc8) throw new FlacException("Invalid frame CRC"); ushort currentCrc16 = CrcUtils.Crc16( CrcUtils.Crc16(0, readData), (byte)headerCrc8); bitReader = new FlacBitStreamReader(BaseStream, currentCrc16); lastFrameHeaderData = new byte[readData.Length + 1]; Array.Copy(readData, lastFrameHeaderData, readData.Length); lastFrameHeaderData[readData.Length] = crc8; recordType = FlacRecordType.Frame; }
public void WriteFrame(FlacMethodAndDataPair[] methods, SoundChannelAssignmentType channelAssignment) { EnsureFramesMode(); sink.StartFrame(streamPosition, currentSample); if (methods == null) throw new ArgumentNullException("methods"); if(methods.Length != Streaminfo.ChannelsCount) throw new ArgumentNullException("Methods items does not correspond to amount of channels"); int samplesCount = methods[0].Data.Length; const byte Blocking = 0x00; // fixed MemoryStream frameHeader = new MemoryStream(); // sync code + reserved = 0 + blocking frameHeader.WriteByte(0xFF); frameHeader.WriteByte(0xF8 | Blocking); int interChannelSamplesTypeIndex = Array.IndexOf(FlacCommons.StaticBlockSizeSamples, samplesCount); int interChannelSamplesType; if (interChannelSamplesTypeIndex > 0) interChannelSamplesType = interChannelSamplesTypeIndex; else if (samplesCount > 256) interChannelSamplesType = FlacCommons.Bit16BlockSizeSamplesType; else interChannelSamplesType = FlacCommons.Bit8BlockSizeSamplesType; int sampleRateTypeIndex = Array.IndexOf(FlacCommons.StaticSampleRates, Streaminfo.SampleRate); int sampleRateType = sampleRateTypeIndex > 0 ? sampleRateTypeIndex : FlacCommons.StreaminfoSampleRateType; frameHeader.WriteByte((byte)(interChannelSamplesType << 4 | sampleRateType)); int channelAssignmetType = (int)channelAssignment; int sampleSizeInBitsTypeIndex = Array.IndexOf(FlacCommons.StaticSampleSizeInBits, Streaminfo.BitsPerSample); int sampleSizeInBitsType = sampleSizeInBitsTypeIndex > 0 ? sampleSizeInBitsTypeIndex : FlacCommons.StreaminfoSizeInBitsType; frameHeader.WriteByte((byte)(channelAssignmetType << 4 | sampleSizeInBitsType << 1)); WriteUtf8Number(frameHeader, frameNumber); switch (interChannelSamplesType) { case FlacCommons.Bit8BlockSizeSamplesType: frameHeader.WriteByte((byte)(samplesCount - 1)); break; case FlacCommons.Bit16BlockSizeSamplesType: frameHeader.WriteByte((byte)((samplesCount - 1) >> 8)); frameHeader.WriteByte((byte)(samplesCount - 1)); break; } frameHeader.Close(); byte[] frameHeaderData = frameHeader.ToArray(); byte crc8 = CrcUtils.Crc8(0, frameHeaderData); BaseStream.Write(frameHeaderData, 0, frameHeaderData.Length); BaseStream.WriteByte(crc8); ++frameNumber; ushort crc16Seed = CrcUtils.Crc16(CrcUtils.Crc16(0, frameHeaderData), crc8); // write channels FlacBitStreamWriter bitWriter = new FlacBitStreamWriter(BaseStream, crc16Seed); for (int i = 0; i < methods.Length; i++) { WriteSubframe(bitWriter, methods[i]); } int subframesLength; ushort crc16; bitWriter.Complete(out crc16, out subframesLength); // write footer BaseStream.WriteByte((byte)(crc16 >> 8)); BaseStream.WriteByte((byte)crc16); int frameSize = frameHeaderData.Length + 1 + subframesLength + 2; streamPosition += frameSize; currentSample += samplesCount; sink.EndFrame(streamPosition, currentSample); }
public void WriteFrame(int[][] samples, SoundChannelAssignmentType channelAssigment) { if(samples == null) throw new ArgumentNullException("samples"); int channelsCount = Streaminfo.ChannelsCount; if (samples.Length != channelsCount) throw new ArgumentException("Expected same amount of channels as in Streaminfo"); int samplesPerChannel = samples[0].Length; if( // samplesPerChannel < Streaminfo.MinBlockSize || Streaminfo.MaxBlockSize < samplesPerChannel) throw new ArgumentException("Amount of samples more or less than specified in Streaminfo"); for (int i = 1; i < channelsCount; i++) { if(samplesPerChannel != samples[i].Length) throw new ArgumentException("Expected same amount of samples on all the channels"); } FlacMethod[] methods; if(channelsCount == 2 && channelAssigment == SoundChannelAssignmentType.Auto) { FlacMethodAndDataPair[] methodsForLeftAndRight; SoundChannelAssignmentType assigmentType = FindBestMethod(samples[0], samples[1], out methodsForLeftAndRight); WriteFrame(methodsForLeftAndRight, assigmentType); } else { methods = new FlacMethod[channelsCount]; SoundChannelAssignment[] assignments; SoundChannelAssignmentType definedChannelAssigmentType; if (channelAssigment == SoundChannelAssignmentType.Auto) { assignments = FlacCommons.StaticChannelAssignments[channelsCount - 1]; definedChannelAssigmentType = (SoundChannelAssignmentType)(channelsCount - 1); } else { assignments = FlacCommons.StaticChannelAssignments[(int)channelAssigment]; definedChannelAssigmentType = channelAssigment; } FlacMethodAndDataPair[] samplesAndMethods = estimator.FindBestMethods( samples, Streaminfo.BitsPerSample); WriteFrame(samplesAndMethods, definedChannelAssigmentType); } }