コード例 #1
0
ファイル: FlacReader.cs プロジェクト: RyosukeOtani/FlacBox
        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;
        }
コード例 #2
0
ファイル: FlacWriter.cs プロジェクト: RyosukeOtani/FlacBox
        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);
        }