public bool Set(
            int numChannels,
            int bitsPerSample,
            int validBitsPerSample,
            int sampleRate,
            PcmDataLib.PcmData.ValueRepresentationType sampleValueRepresentation,
            long numFrames,
            byte[] sampleArray)
        {
            mRcd = new RiffChunkDescriptor();

            if (0xffffffffL < sampleArray.LongLength + 36) {
                System.Diagnostics.Debug.Assert(false);
                return false;
            }
            mRcd.Create((uint)(36 + sampleArray.LongLength));

            mFsc = new FmtSubChunk();
            mFsc.Create(numChannels, sampleRate, bitsPerSample, validBitsPerSample, sampleValueRepresentation);

            var dsc = new WavDataSubChunk();
            dsc.Create(numFrames, sampleArray);
            mDscList.Clear();
            mDscList.Add(dsc);
            return true;
        }
Example #2
0
        /// <summary>
        /// writes PCM data onto WAV file
        /// </summary>
        public bool Write(BinaryWriter bw,
                int numChannels,
                int bitsPerSample,
                int validBitsPerSample,
                int sampleRate,
                PcmDataLib.PcmData.ValueRepresentationType sampleValueRepresentation,
                long numFrames,
                byte[] sampleArray)
        {
            if (0xffffffffL < sampleArray.LongLength + 36) {
                System.Diagnostics.Debug.Assert(false);
                return false;
            }

            int dwChannelMask = 0;
            if (numChannels == 2) {
                dwChannelMask = 3;
            }

            mLL.RiffChunkWrite(bw, (int)(36 + sampleArray.LongLength));
            mLL.FmtChunkWriteExtensible(bw, (short)numChannels, (int)sampleRate,
                    (short)bitsPerSample, (short)validBitsPerSample, sampleValueRepresentation, dwChannelMask);
            mLL.DataChunkWrite(bw, false, sampleArray);
            return true;
        }
Example #3
0
        public void FmtChunkWriteExtensible(BinaryWriter bw,
               short numChannels, int sampleRate, short bitsPerSample, short validBitsPerSample,
               PcmDataLib.PcmData.ValueRepresentationType sampleValueRepresentation, int dwChannelMask)
        {
            FmtChunkWriteInternal(bw, numChannels, sampleRate, bitsPerSample, 40, WAVE_FORMAT_EXTENSIBLE);

            ushort cbSize = 22;
            bw.Write(cbSize);
            bw.Write(validBitsPerSample);
            bw.Write(dwChannelMask);

            byte[] guidByteArray = null;
            if (sampleValueRepresentation == PcmDataLib.PcmData.ValueRepresentationType.SInt) {
                var pcmGuid = Guid.Parse("00000001-0000-0010-8000-00aa00389b71");
                guidByteArray = pcmGuid.ToByteArray();
            } else if (sampleValueRepresentation == PcmDataLib.PcmData.ValueRepresentationType.SFloat) {
                var floatGuid = Guid.Parse("00000003-0000-0010-8000-00aa00389b71");
                guidByteArray = floatGuid.ToByteArray();
            } else {
                throw new ArgumentException("sampleValueRepresentation");
            }
            bw.Write(guidByteArray);
        }
        public int ReadHeader(string flacFilePath, out PcmDataLib.PcmData pcmData_return, out List<FlacCuesheetTrackInfo> cueSheet_return)
        {
            int rv = ReadStartCommon(ReadMode.Header, flacFilePath, 0, 0, out pcmData_return, out cueSheet_return);
            StopChildProcess();
            if (rv != 0) {
                return rv;
            }

            return 0;
        }
Example #5
0
        public ResultType ReadStreamBegin(BinaryReader br, out PcmDataLib.PcmData pcmData)
        {
            ResultType rt = ResultType.Success;
            rt = ReadHeader1(br, out pcmData, ReadHeaderMode.ReadStopBeforeSoundData);
            mPosFrame = 0;

            return rt;
        }
Example #6
0
        private ResultType ReadHeader1(BinaryReader br, out PcmDataLib.PcmData pcmData, ReadHeaderMode mode)
        {
            pcmData = new PcmDataLib.PcmData();

            ResultType result = ReadDsfChunk(br);
            if (result != ResultType.Success) {
                return result;
            }

            result = ReadFmtChunk(br);
            if (ResultType.Success != result) {
                return result;
            }

            result = ReadDataChunkHeader(br);
            if (ResultType.Success != result) {
                return result;
            }

            // 読み込めるデータのフレーム数DataFramesと出力するデータのフレーム数OutputFrames。
            // PCMデータのフレーム数OutputFramesは偶数個にする。
            OutputFrames = mDataFrames;
            if (0 != (1 & OutputFrames)) {
                // OutputFrames must be even number
                ++OutputFrames;
            }

            pcmData.SetFormat(
                NumChannels,
                24,
                24,
                SampleRate/16,
                PcmDataLib.PcmData.ValueRepresentationType.SInt,
                OutputFrames);
            pcmData.SampleDataType = PcmDataLib.PcmData.DataType.DoP;

            if (mode == ReadHeaderMode.AllHeadersWithID3 &&
                mMetadataOffset != 0) {
                PcmDataLib.Util.BinaryReaderSkip(br, (long)mMetadataOffset - STREAM_DATA_OFFSET);

                result = ReadID3Chunk(br);
                if (ResultType.Success == result) {
                    // ID3読み込み成功
                    pcmData.DisplayName = TitleName;
                    pcmData.AlbumTitle = AlbumName;
                    pcmData.ArtistName = ArtistName;
                    if (0 < PictureBytes) {
                        pcmData.SetPicture(PictureBytes, PictureData);
                    }
                }
            }

            return 0;
        }
Example #7
0
        private ResultType ReadHeader1(BinaryReader br, out PcmDataLib.PcmData pcmData, ReadHeaderMode mode)
        {
            pcmData = new PcmDataLib.PcmData();

            ResultType result = ReadFormChunkHeader(br);
            if (result != ResultType.Success) {
                return result;
            }

            if (mIsAIFC) {
                // AIFCの場合、FVERチャンクが来る(required)
                result = ReadFverChunk(br);
                if (ResultType.Success != result) {
                    return result;
                }
            }

            result = ReadCommonChunk(br);
            if (ResultType.Success != result) {
                return result;
            }

            result = ReadSoundDataChunk(br, mode);
            if (ResultType.Success != result) {
                return result;
            }

            if (16 != BitsPerSample &&
                24 != BitsPerSample) {
                return ResultType.NotSupportBitsPerSample;
            }

            pcmData.SetFormat(
                NumChannels,
                BitsPerSample,
                BitsPerSample,
                SampleRate,
                PcmDataLib.PcmData.ValueRepresentationType.SInt,
                NumFrames);

            if (mode == ReadHeaderMode.AllHeadersWithID3) {
                result = ReadID3Chunk(br);
                if (ResultType.Success == result) {
                    // ID3読み込み成功
                    pcmData.DisplayName = TitleName;
                    pcmData.AlbumTitle = AlbumName;
                    pcmData.ArtistName = ArtistName;
                    if (0 < PictureBytes) {
                        pcmData.SetPicture(PictureBytes, PictureData);
                    }
                }
            }

            return 0;
        }
Example #8
0
 public ResultType ReadHeader(BinaryReader br, out PcmDataLib.PcmData pcmData)
 {
     return ReadHeader1(br, out pcmData, ReadHeaderMode.AllHeadersWithID3);
 }
        private ResultType ReadHeader1(BinaryReader br, ReadHeaderMode mode, out PcmDataLib.PcmData pcmData)
        {
            pcmData = new PcmDataLib.PcmData();
            bool done = false;

            try {
                while (!done) {
                    ResultType rt = ResultType.Success;
                    uint fourCC = br.ReadUInt32();
                    switch (fourCC) {
                    case FOURCC_FRM8:
                        rt = ReadDsdChunk(br);
                        break;
                    case FOURCC_FVER:
                        rt = ReadFormVersionChunk(br);
                        break;
                    case FOURCC_PROP:
                        rt = ReadPropertyChunk(br);
                        break;
                    case FOURCC_FS:
                        rt = ReadSampleRateChunk(br);
                        break;
                    case FOURCC_CHNL:
                        rt = ReadChannelsChunk(br);
                        break;
                    case FOURCC_CMPR:
                        rt = ReadCompressionTypeChunk(br);
                        break;
                    case FOURCC_DSD:
                        rt = ReadSoundDataChunkHeader(br, mode);
                        switch (mode) {
                        case ReadHeaderMode.ReadStopBeforeSoundData:
                            done = true;
                            break;
                        case ReadHeaderMode.AllHeadersWithID3:
                            break;
                        }
                        break;
                    case FOURCC_ID3:
                        rt = ReadID3Chunk(br);
                        break;
                    default:
                        rt = SkipUnknownChunk(br);
                        break;
                    }
                    if (rt != ResultType.Success) {
                        return rt;
                    }
                }
            } catch (EndOfStreamException ex) {
                // this is only way to exit from the while loop above
                System.Console.WriteLine(ex);
            }

            if (0 == SampleRate ||   // SampleRateChunkが存在しないとき。
                2 != NumChannels ||
                0 == mDataFrames) {
                return ResultType.ReadError;
            }

            // 読み込めるデータのフレーム数DataFramesと出力するデータのフレーム数OutputFrames。
            // PCMデータのフレーム数OutputFramesは偶数個にする。
            OutputFrames = mDataFrames;
            if (0 != (1 & OutputFrames)) {
                // OutputFrames must be even number
                ++OutputFrames;
            }

            pcmData.SetFormat(
                NumChannels,
                24,
                24,
                SampleRate/16,
                PcmDataLib.PcmData.ValueRepresentationType.SInt,
                OutputFrames);
            pcmData.SampleDataType = PcmDataLib.PcmData.DataType.DoP;

            if (null != TitleName) {
                pcmData.DisplayName = TitleName;
            }
            if (null != AlbumName) {
                pcmData.AlbumTitle = AlbumName;
            }
            if (null != ArtistName) {
                pcmData.ArtistName = ArtistName;
            }
            if (0 < PictureBytes) {
                pcmData.SetPicture(PictureBytes, PictureData);
            }

            return 0;
        }
Example #10
0
        /// <summary>
        /// カバーアート画像を追加する。
        /// </summary>
        /// <returns>true: カバーアート画像が付いている。false: カバーアート画像がついていない。</returns>
        private bool AddCoverart(string path, PcmDataLib.PcmData pcmData)
        {
            if (0 < pcmData.PictureBytes) {
                // 既に追加されている。
                return true;
            }

            try {
                var dirPath = System.IO.Path.GetDirectoryName(path);

                var pictureData = ReadWholeFile(string.Format(CultureInfo.InvariantCulture, "{0}\\{1}.jpg", dirPath,
                        System.IO.Path.GetFileNameWithoutExtension(path)));
                if (0 < pictureData.Length) {
                    // ファイル名.jpgが存在。
                    pcmData.SetPicture(pictureData.Length, pictureData);
                    return true;
                }

                foreach (string albumImageFilename in ALBUM_IMAGE_FILENAMES) {
                    pictureData = ReadWholeFile(string.Format(CultureInfo.InvariantCulture, "{0}\\{1}", dirPath, albumImageFilename));
                    if (0 < pictureData.Length) {
                        // アルバムのカバーアート画像(folder.jpg等)が存在。
                        pcmData.SetPicture(pictureData.Length, pictureData);
                        return true;
                    }
                }
            } catch (Exception ex) {
                // エラーが起きたら読まない。
                LoadErrorMessageAdd(string.Format(CultureInfo.InvariantCulture, "W: coverart image read failed: {0}", ex));
            }

            return false;
        }
Example #11
0
 public PlayListItemInfo(PcmDataLib.PcmData pcmData)
 {
     mPcmData = pcmData;
     mRowId = mNextRowId++;
 }
Example #12
0
        public bool Create(
            int numChannels, int sampleRate, int bitsPerSample, int validBitsPerSample,
            PcmDataLib.PcmData.ValueRepresentationType sampleValueRepresentation)
        {
            m_subChunk1Id = new byte[4];
            m_subChunk1Id[0] = (byte)'f';
            m_subChunk1Id[1] = (byte)'m';
            m_subChunk1Id[2] = (byte)'t';
            m_subChunk1Id[3] = (byte)' ';

            m_subChunk1Size = 16;

            m_audioFormat = 1;

            System.Diagnostics.Debug.Assert(0 < numChannels);
            NumChannels = (ushort)numChannels;

            SampleRate = (uint)sampleRate;
            m_byteRate = (uint)(sampleRate * numChannels * bitsPerSample / 8);
            m_blockAlign = (ushort)(numChannels * bitsPerSample / 8);

            BitsPerSample = (ushort)bitsPerSample;
            ValidBitsPerSample = (ushort)validBitsPerSample;
            ChannelMask = 0;

            SampleValueRepresentationType = sampleValueRepresentation;
            if (sampleValueRepresentation == PcmDataLib.PcmData.ValueRepresentationType.SInt) {
                m_audioFormat = 1;
            } else if (sampleValueRepresentation == PcmDataLib.PcmData.ValueRepresentationType.SFloat) {
                m_audioFormat = 3;
            } else {
                System.Diagnostics.Debug.Assert(false);
            }

            return true;
        }
        /// <summary>
        /// PcmDataの形式と、(共有・排他)、フォーマット固定設定から、
        /// デバイスに設定されるビットフォーマットを取得。
        /// 
        /// これは、内容的にテーブルなので、テーブルにまとめたほうが良い。
        /// </summary>
        /// <returns>デバイスに設定されるビットフォーマット</returns>
        public static SampleFormatInfo CreateSetupSampleFormat(
            WasapiSharedOrExclusiveType sharedOrExclusive,
            BitsPerSampleFixType bitsPerSampleFixType,
            int bitsPerSample,
            int validBitsPerSample,
            PcmDataLib.PcmData.ValueRepresentationType vrt,
            int candidateId)
        {
            SampleFormatInfo sf = new SampleFormatInfo();

            if (sharedOrExclusive == WasapiSharedOrExclusiveType.Shared) {
                // 共有モード
                sf.bitsPerSample = bitsPerSample;
                sf.validBitsPerSample = validBitsPerSample;
                sf.bitFormatType = SampleFormatInfo.VrtToBft(vrt);
                return sf;
            }

            // 排他モード
            switch (bitsPerSampleFixType) {
            case BitsPerSampleFixType.Sint16:
                sf.bitFormatType = WasapiCS.BitFormatType.SInt;
                sf.bitsPerSample = 16;
                sf.validBitsPerSample = 16;
                break;
            case BitsPerSampleFixType.Sint24:
                sf.bitFormatType = WasapiCS.BitFormatType.SInt;
                sf.bitsPerSample = 24;
                sf.validBitsPerSample = 24;
                break;
            case BitsPerSampleFixType.Sint32:
                sf.bitFormatType = WasapiCS.BitFormatType.SInt;
                sf.bitsPerSample = 32;
                sf.validBitsPerSample = 32;
                break;
            case BitsPerSampleFixType.Sint32V24:
                sf.bitFormatType = WasapiCS.BitFormatType.SInt;
                sf.bitsPerSample = 32;
                sf.validBitsPerSample = 24;
                break;
            case BitsPerSampleFixType.Sfloat32:
                sf.bitFormatType = WasapiCS.BitFormatType.SFloat;
                sf.bitsPerSample = 32;
                sf.validBitsPerSample = 32;
                break;
            case BitsPerSampleFixType.AutoSelect:
                WasapiCS.SampleFormatType sampleFormat = WasapiCS.SampleFormatType.Sint16;
                switch (validBitsPerSample) {
                case 16:
                    sampleFormat = mTryFormat16[candidateId];
                    break;
                case 24:
                default: /* ? */
                    sampleFormat = mTryFormat24[candidateId];
                    break;
                case 32:
                    sampleFormat = mTryFormat32[candidateId];
                    break;
                }

                sf.bitFormatType      = WasapiCS.BitFormatType.SInt;
                sf.bitsPerSample      = WasapiCS.SampleFormatTypeToUseBitsPerSample(sampleFormat);
                sf.validBitsPerSample = WasapiCS.SampleFormatTypeToValidBitsPerSample(sampleFormat);
                break;
            default:
                System.Diagnostics.Debug.Assert(false);
                break;
            }

            return sf;
        }
        /// <summary>
        /// フォーマット設定から、
        /// Setup()に設定されうるビットフォーマットの候補の数を数えて戻す。
        /// </summary>
        /// <returns>Setup()に設定されうるビットフォーマットの候補の数</returns>
        public static int GetSetupSampleFormatCandidateNum(
            WasapiSharedOrExclusiveType sharedOrExclusive,
            BitsPerSampleFixType bitsPerSampleFixType,
            int validBitsPerSample,
            PcmDataLib.PcmData.ValueRepresentationType vrt)
        {
            if (bitsPerSampleFixType != BitsPerSampleFixType.AutoSelect ||
                    sharedOrExclusive == WasapiSharedOrExclusiveType.Shared) {
                // 共有モードの場合 1通り
                // 排他モードで自動選択以外の選択肢の場合 1通り
                return 1;
            }

            // 排他モードのAutoSelect
            switch (validBitsPerSample) {
            case 16:
                return mTryFormat16.Length;
            case 24:
            default:
                return mTryFormat24.Length;
            case 32:
                return mTryFormat32.Length;
            }
        }
Example #15
0
        /// <summary>
        /// メタ情報更新。PcmData読み込み成功後に行う。
        /// FLACとWAVとAIFFで共通。
        /// </summary>
        private bool CheckAddPcmData(string path, PcmDataLib.PcmData pcmData, bool bUsePlaylistTrackInfo)
        {
            if (31 < pcmData.NumChannels) {
                LoadErrorMessageAdd(string.Format(CultureInfo.InvariantCulture, "{0}: {1} {2}ch{3}",
                        Properties.Resources.TooManyChannels, path, pcmData.NumChannels, Environment.NewLine));
                return false;
            }

            if (pcmData.BitsPerSample != 16
                    && pcmData.BitsPerSample != 24
                    && pcmData.BitsPerSample != 32) {
                LoadErrorMessageAdd(string.Format(CultureInfo.InvariantCulture, "{0}: {1} {2}bit{3}",
                        Properties.Resources.NotSupportedQuantizationBitRate, path, pcmData.BitsPerSample, Environment.NewLine));
                return false;
            }

            pcmData.FullPath = path;
            pcmData.FileName = System.IO.Path.GetFileName(path);
            pcmData.LastWriteTime = System.IO.File.GetLastWriteTimeUtc(path).Ticks;

            // PCMファイルにタイトル名が埋め込まれていない時、ファイル名をタイトル名にする。
            if (pcmData.DisplayName == null || pcmData.DisplayName.Length == 0) {
                pcmData.DisplayName = pcmData.FileName;
            }

            if (!bUsePlaylistTrackInfo || null == mPlaylistTrackMeta) {
                // startTickとendTickは、既にセットされていることもあるので、ここではセットしない。
                // pcmData.StartTick     = 0;
                // pcmData.EndTick       = -1;
                // pcmData.CueSheetIndex = 1;
            } else {
                pcmData.StartTick     = mPlaylistTrackMeta.startTick;
                pcmData.EndTick       = mPlaylistTrackMeta.endTick;
                pcmData.CueSheetIndex = mPlaylistTrackMeta.indexId;

                // 再生リストにタイトル名情報がある時は、再生リストのタイトル名をタイトル名にする。
                if (mPlaylistTrackMeta.title != null && 0 < mPlaylistTrackMeta.title.Length) {
                    pcmData.DisplayName = mPlaylistTrackMeta.title;
                }

                if (mPlaylistTrackMeta.performer != null && 0 < mPlaylistTrackMeta.performer.Length) {
                    pcmData.ArtistName = mPlaylistTrackMeta.performer;
                }
                if (mPlaylistTrackMeta.albumTitle != null && 0 < mPlaylistTrackMeta.albumTitle.Length) {
                    pcmData.AlbumTitle = mPlaylistTrackMeta.albumTitle;
                }
            }

            bool readSeparatorAfter = false;
            if (mPlis != null) {
                // PPWプレイリストの情報で上書きする
                pcmData.DisplayName = mPlis.Title;
                pcmData.AlbumTitle = mPlis.AlbumName;
                pcmData.ArtistName = mPlis.ArtistName;
                pcmData.StartTick = mPlis.StartTick;
                pcmData.EndTick = mPlis.EndTick;
                pcmData.CueSheetIndex = mPlis.CueSheetIndex;
                readSeparatorAfter = mPlis.ReadSeparaterAfter;
            }

            // カバーアート画像を追加する
            AddCoverart(path, pcmData);

            mAddPcmData(pcmData, readSeparatorAfter, mPlis != null);
            return true;
        }
        /// <summary>
        /// FLACファイルからPCMデータを取り出し開始。
        /// </summary>
        /// <param name="flacFilePath">読み込むファイルパス。</param>
        /// <param name="skipFrames">ファイルの先頭からのスキップするフレーム数。0以外の値を指定するとMD5のチェックが行われなくなる。</param>
        /// <param name="wantFrames">取得するフレーム数。</param>
        /// <param name="pcmData">出てきたデコード後のPCMデータ。</param>
        /// <returns>0: 成功。負: 失敗。</returns>
        public int ReadStreamBegin(string flacFilePath, long skipFrames, long wantFrames, int typicalReadFrames, out PcmDataLib.PcmData pcmData_return)
        {
            List<FlacCuesheetTrackInfo> cti;
            int rv = ReadStartCommon(ReadMode.HeadereAndData, flacFilePath, skipFrames, wantFrames, out pcmData_return, out cti);
            if (rv != 0) {
                StopChildProcess();
                mBytesPerFrame = 0;
                return rv;
            }

            mBytesPerFrame = pcmData_return.BitsPerFrame / 8;

            if (CalcMD5 && skipFrames == 0 && wantFrames == mNumFrames) {
                md5 = new MD5CryptoServiceProvider();
                mMD5SumOfPcm = new byte[MD5_BYTES];
                mMD5TmpBuffer = new byte[mBytesPerFrame * typicalReadFrames];
            }

            return 0;
        }
Example #17
0
        private int WasapiSetup(
            int deviceId,
            bool isExclusive,
            bool isEventDriven,
            int sampleRate,
            int pcmDataBitsPerSample,
            int pcmDataValidBitsPerSample,
            PcmDataLib.PcmData.ValueRepresentationType vrt,
            int latencyMillisec)
        {
            int num = SampleFormatInfo.GetSetupSampleFormatCandidateNum(
                isExclusive ? WasapiSharedOrExclusiveType.Exclusive : WasapiSharedOrExclusiveType.Shared,
                BitsPerSampleFixType.AutoSelect,
                pcmDataValidBitsPerSample, vrt);

            int hr = -1;
            for (int i = 0; i < num; ++i) {
                SampleFormatInfo sf = SampleFormatInfo.CreateSetupSampleFormat(
                    isExclusive ? WasapiSharedOrExclusiveType.Exclusive : WasapiSharedOrExclusiveType.Shared,
                    BitsPerSampleFixType.AutoSelect,
                    pcmDataBitsPerSample,
                    pcmDataValidBitsPerSample, vrt, i);

                hr = wasapi.Setup(deviceId, WasapiCS.DeviceType.Play, WasapiCS.StreamType.PCM, sampleRate,
                        sf.GetSampleFormatType(), 2, WasapiCS.MMCSSCallType.Enable, WasapiCS.MMThreadPriorityType.None,
                        WasapiCS.SchedulerTaskType.ProAudio, WasapiCS.ShareMode.Exclusive,
                        isEventDriven ? WasapiCS.DataFeedMode.EventDriven : WasapiCS.DataFeedMode.TimerDriven,
                        latencyMillisec, 500, 10000);
                if (0 <= hr) {
                    m_sampleFormat = sf;
                    return hr;
                }
            }
            wasapi.Unsetup();
            return hr;
        }
        private int ReadStartCommon(ReadMode mode, string flacFilePath, long skipFrames, long wantFrames,
            out PcmDataLib.PcmData pcmData_return, out List<FlacCuesheetTrackInfo> cueSheet_return)
        {
            pcmData_return = new PcmDataLib.PcmData();
            cueSheet_return = new List<FlacCuesheetTrackInfo>();

            StartChildProcess();

            switch (mode) {
            case ReadMode.Header:
                SendString("H");
                SendBase64(flacFilePath);
                break;
            case ReadMode.HeadereAndData:
                SendString("A");
                SendBase64(flacFilePath);
                SendString(skipFrames.ToString(CultureInfo.InvariantCulture));
                SendString(wantFrames.ToString(CultureInfo.InvariantCulture));
                break;
            default:
                System.Diagnostics.Debug.Assert(false);
                break;
            }

            int rv = mBinaryReader.ReadInt32();
            if (rv != 0) {
                return rv;
            }

            int nChannels     = mBinaryReader.ReadInt32();
            int bitsPerSample = mBinaryReader.ReadInt32();
            int sampleRate    = mBinaryReader.ReadInt32();

            mNumFrames         = mBinaryReader.ReadInt64();
            int numFramesPerBlock = mBinaryReader.ReadInt32();

            string titleStr = mBinaryReader.ReadString();
            string albumStr = mBinaryReader.ReadString();
            string artistStr = mBinaryReader.ReadString();

            byte md5Available = mBinaryReader.ReadByte();
            md5MetaAvailable = md5Available != 0;

            mMD5SumInMetadata = mBinaryReader.ReadBytes(MD5_BYTES);

            mPictureBytes = mBinaryReader.ReadInt32();
            mPictureData = new byte[0];
            if (0 < mPictureBytes) {
                mPictureData = mBinaryReader.ReadBytes(mPictureBytes);
            }

            {
                int numCuesheetTracks = mBinaryReader.ReadInt32();
                for (int trackId=0; trackId < numCuesheetTracks; ++trackId) {
                    var cti = new FlacCuesheetTrackInfo();
                    cti.trackNr = mBinaryReader.ReadInt32();
                    cti.offsetSamples = mBinaryReader.ReadInt64();

                    int numCuesheetTrackIndices = mBinaryReader.ReadInt32();
                    for (int indexId=0; indexId < numCuesheetTrackIndices; ++indexId) {
                        var indexInfo = new FlacCuesheetTrackIndexInfo();
                        indexInfo.indexNr = mBinaryReader.ReadInt32();
                        indexInfo.offsetSamples = mBinaryReader.ReadInt64();
                        cti.indices.Add(indexInfo);
                    }
                    cueSheet_return.Add(cti);
                }
            }

            pcmData_return.SetFormat(
                nChannels,
                bitsPerSample,
                bitsPerSample,
                sampleRate,
                PcmDataLib.PcmData.ValueRepresentationType.SInt,
                mNumFrames);

            pcmData_return.DisplayName = titleStr;
            pcmData_return.AlbumTitle = albumStr;
            pcmData_return.ArtistName = artistStr;

            pcmData_return.SetPicture(mPictureBytes, mPictureData);
            return 0;
        }
        public bool ReadStreamBegin(BinaryReader br, out PcmDataLib.PcmData pcmData)
        {
            if (!ReadHeader(br)) {
                pcmData = new PcmDataLib.PcmData();
                return false;
            }

            pcmData = new PcmDataLib.PcmData();
            pcmData.SetFormat(NumChannels, BitsPerSample,
                    BitsPerSample, (int)SampleRate,
                    SampleValueRepresentationType, NumFrames);

            mCurrentDsc = -1;
            mDscPosFrame = 0;

            // 最初のDSCまでシークする。
            return ReadStreamSkip(br, 0);
        }