Пример #1
0
        public PcmData MonoToStereo()
        {
            System.Diagnostics.Debug.Assert(NumChannels == 1);

            // サンプルあたりビット数が8の倍数でないとこのアルゴリズムは使えない
            System.Diagnostics.Debug.Assert((BitsPerSample & 7) == 0);

            var newSampleArray = new WWUtil.LargeArray <byte>(mSampleLargeArray.LongLength * 2);

            {
                int bytesPerSample = BitsPerSample / 8;

                // sampleArrayのフレーム数はこれよりも少ないことがある。
                // 実際に存在するサンプル数sampleFramesだけ処理する。
                long sampleFrames = mSampleLargeArray.LongLength / bytesPerSample; // NumChannels==1なので。
                long fromPosBytes = 0;
                for (long frame = 0; frame < sampleFrames; ++frame)
                {
                    for (int offs = 0; offs < bytesPerSample; ++offs)
                    {
                        byte b = mSampleLargeArray.At(fromPosBytes + offs);
                        newSampleArray.Set(fromPosBytes * 2 + offs, b);
                        newSampleArray.Set(fromPosBytes * 2 + bytesPerSample + offs, b);
                    }
                    fromPosBytes += bytesPerSample;
                }
            }
            PcmData newPcmData = new PcmData();

            newPcmData.CopyHeaderInfoFrom(this);
            newPcmData.SetFormat(2, BitsPerSample, ValidBitsPerSample, SampleRate, SampleValueRepresentationType, NumFrames);
            newPcmData.SetSampleLargeArray(newSampleArray);

            return(newPcmData);
        }
Пример #2
0
 /// <summary>
 /// rhsの内容をコピーする。PCMデータ配列だけはコピーしない。(nullをセットする)
 /// PCMデータ配列は、SetSampleArrayで別途設定する。
 /// </summary>
 /// <param name="rhs">コピー元</param>
 public void CopyHeaderInfoFrom(PcmData rhs)
 {
     NumChannels                   = rhs.NumChannels;
     SampleRate                    = rhs.SampleRate;
     BitsPerSample                 = rhs.BitsPerSample;
     ValidBitsPerSample            = rhs.ValidBitsPerSample;
     SampleValueRepresentationType = rhs.SampleValueRepresentationType;
     mNumFrames                    = rhs.mNumFrames;
     mSampleLargeArray             = null;
     Id             = rhs.Id;
     Ordinal        = rhs.Ordinal;
     GroupId        = rhs.GroupId;
     FileName       = rhs.FileName;
     FullPath       = rhs.FullPath;
     DisplayName    = rhs.DisplayName;
     StartTick      = rhs.StartTick;
     EndTick        = rhs.EndTick;
     AlbumTitle     = rhs.AlbumTitle;
     ArtistName     = rhs.ArtistName;
     ComposerName   = rhs.ComposerName;
     CueSheetIndex  = rhs.CueSheetIndex;
     PictureBytes   = rhs.PictureBytes;
     PictureData    = rhs.PictureData;
     SampleDataType = rhs.SampleDataType;
     LastWriteTime  = rhs.LastWriteTime;
     TrackId        = rhs.TrackId;
 }
Пример #3
0
 /// <summary>
 /// サンプリング周波数と量子化ビット数、有効なビット数、チャンネル数、データ形式が同じならtrue
 /// </summary>
 public bool IsSameFormat(PcmData other)
 {
     return(BitsPerSample == other.BitsPerSample &&
            ValidBitsPerSample == other.ValidBitsPerSample &&
            SampleRate == other.SampleRate &&
            NumChannels == other.NumChannels &&
            SampleValueRepresentationType == other.SampleValueRepresentationType &&
            SampleDataType == other.SampleDataType);
 }
Пример #4
0
        /// <summary>
        /// ヘッダー情報、サンプルデータ領域をクローンする。
        /// </summary>
        public void CopyFrom(PcmData rhs)
        {
            CopyHeaderInfoFrom(rhs);

            mSampleLargeArray = null;
            if (rhs.mSampleLargeArray != null)
            {
                mSampleLargeArray = rhs.mSampleLargeArray.Clone();
            }
        }
Пример #5
0
        /// <summary>
        /// WAVファイルのヘッダ部分を読み込む。
        /// </summary>
        /// <returns>読めたらtrue</returns>
        private bool ReadWavFileHeader(string path)
        {
            bool result = false;
            var  pd     = new PcmDataLib.PcmData();

            var wavR = new WavReader();

            using (BinaryReader br = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))) {
                if (wavR.ReadHeader(br))
                {
                    // WAVヘッダ読み込み成功。PcmDataを作って再生リストに足す。

                    pd.SetFormat(wavR.NumChannels, wavR.BitsPerSample, wavR.ValidBitsPerSample,
                                 (int)wavR.SampleRate, wavR.SampleValueRepresentationType, wavR.NumFrames);
                    if ("RIFFINFO_INAM".Equals(wavR.Title) &&
                        "RIFFINFO_IART".Equals(wavR.ArtistName))
                    {
                        // Issue 79 workaround
                    }
                    else
                    {
                        if (wavR.Title != null)
                        {
                            pd.DisplayName = wavR.Title;
                        }
                        if (wavR.AlbumName != null)
                        {
                            pd.AlbumTitle = wavR.AlbumName;
                        }
                        if (wavR.ArtistName != null)
                        {
                            pd.ArtistName = wavR.ArtistName;
                        }
                    }
                    pd.SetPicture(wavR.PictureBytes, wavR.PictureData);
                    result = CheckAddPcmData(path, pd, true);
                }
                else
                {
                    LoadErrorMessageAdd(string.Format(CultureInfo.InvariantCulture, Properties.Resources.ReadFileFailed + ": {1} : {2}{3}",
                                                      "WAV", path, wavR.ErrorReason, Environment.NewLine));
                }
            }

            return(result);
        }
Пример #6
0
        public static PcmData ReadWav(BinaryReader br)
        {
            var reader = new WavReader();
            if (!reader.ReadHeaderAndSamples(br, 0, -1)) {
                return null;
            }

            var pcm = new PcmData();
            pcm.AlbumTitle = reader.AlbumName;
            pcm.ArtistName = reader.ArtistName;
            pcm.DisplayName = reader.Title;

            pcm.SetFormat(reader.NumChannels, reader.BitsPerSample,
                reader.ValidBitsPerSample, reader.SampleRate,
                reader.SampleValueRepresentationType, reader.NumFrames);

            pcm.SetSampleArray(reader.GetSampleArray());

            return pcm;
        }
Пример #7
0
        private bool ReadMp3FileHeader(string path)
        {
            bool result = false;
            var  pd     = new PcmDataLib.PcmData();

            WWMFReader.Metadata meta;
            int rv = WWMFReader.ReadHeader(path, out meta);

            if (0 <= rv)
            {
                pd.SetFormat(meta.numChannels, meta.bitsPerSample, meta.bitsPerSample, meta.sampleRate,
                             PcmData.ValueRepresentationType.SInt, meta.numApproxFrames);
                pd.SampleDataType = PcmDataLib.PcmData.DataType.PCM;
                pd.DisplayName    = meta.title;
                pd.AlbumTitle     = meta.album;
                pd.ArtistName     = meta.artist;
                pd.ComposerName   = meta.composer;
                if (null != meta.picture)
                {
                    pd.SetPicture(meta.picture.Length, meta.picture);
                }

                pd.BitRate           = meta.bitRate;
                pd.IsLossyCompressed = true;

                if (CheckAddPcmData(path, pd, true))
                {
                    result = true;
                }
            }
            else
            {
                LoadErrorMessageAdd(string.Format(CultureInfo.InvariantCulture, Properties.Resources.ReadFileFailed + " {1}: {2}{3}",
                                                  "MP3", rv, path, Environment.NewLine));
            }

            return(result);
        }
Пример #8
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);
        }
Пример #9
0
 /// <summary>
 /// rhsの内容をコピーする。PCMデータ配列だけはコピーしない。(nullをセットする)
 /// PCMデータ配列は、SetSampleArrayで別途設定する。
 /// </summary>
 /// <param name="rhs">コピー元</param>
 public void CopyHeaderInfoFrom(PcmData rhs)
 {
     NumChannels   = rhs.NumChannels;
     SampleRate    = rhs.SampleRate;
     BitsPerSample = rhs.BitsPerSample;
     ValidBitsPerSample = rhs.ValidBitsPerSample;
     SampleValueRepresentationType = rhs.SampleValueRepresentationType;
     mNumFrames = rhs.mNumFrames;
     mSampleArray = null;
     Id          = rhs.Id;
     Ordinal     = rhs.Ordinal;
     GroupId     = rhs.GroupId;
     FileName    = rhs.FileName;
     FullPath    = rhs.FullPath;
     DisplayName = rhs.DisplayName;
     StartTick   = rhs.StartTick;
     EndTick     = rhs.EndTick;
     AlbumTitle  = rhs.AlbumTitle;
     ArtistName   = rhs.ArtistName;
     CueSheetIndex = rhs.CueSheetIndex;
     PictureBytes = rhs.PictureBytes;
     PictureData = rhs.PictureData;
     SampleDataType = rhs.SampleDataType;
     LastWriteTime = rhs.LastWriteTime;
 }
        private void m_AnalyticSignalWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            AnalyticSignalWorkerArgs args = e.Argument as AnalyticSignalWorkerArgs;

            Stopwatch sw = new Stopwatch();
            sw.Start();

            // pcmファイルを読み込んでサンプル配列pcm1chを作成。
            PcmData pcmDataIn = null;
            try {
                pcmDataIn = ReadWavFile(args.inputPath);
            } catch (IOException ex) {
                e.Result = string.Format("WAVファイル {0} 読み込み失敗\r\n{1}", args.inputPath, ex);
            }
            if (null == pcmDataIn) {
                e.Result = string.Format("WAVファイル {0} 読み込み失敗", args.inputPath);
            }

            var formatConv = new WasapiPcmUtil.PcmFormatConverter(pcmDataIn.NumChannels);
            PcmData pcmDataReal = formatConv.Convert(pcmDataIn, Wasapi.WasapiCS.SampleFormatType.Sdouble, null);

            PcmData pcmDataImaginary = new PcmData();
            pcmDataImaginary.CopyFrom(pcmDataReal);

            var dft = new WWDirectComputeCS.WWDftCpu();

            var hilb = WWHilbert.HilbertFirCoeff(args.hilbertFilterType, args.firLength);
            System.Diagnostics.Debug.Assert(hilb.Length == args.firLength);

            // 窓関数
            double [] window;
            if (args.windowFunc == WindowFuncType.Blackman) {
                WWWindowFunc.BlackmanWindow(args.firLength, out window);
            } else {
                WWWindowFunc.KaiserWindow(args.firLength, args.kaiserAlpha, out window);
            }

            // FIR coeffの個数は、window.Length個。
            // ヒルベルト変換パラメータは未来から過去の方向に並んでいるので左右をひっくり返す。
            double [] coeff = new double[args.firLength];
            for (int i=0; i < coeff.Length; ++i) {
                int pos = coeff.Length - i - 1;
                coeff[i] = hilb[pos] * window[i];
            }

            for (int ch=0; ch < pcmDataImaginary.NumChannels; ++ch) {
                var pcm1ch = new double[pcmDataImaginary.NumFrames];
                for (long i=0; i < pcm1ch.Length; ++i) {
                    pcm1ch[i] = pcmDataImaginary.GetSampleValueInDouble(ch, i);
                }

                // 少しずつFIRする。
                var fir = new WWFirCpu();
                fir.Setup(coeff, pcm1ch);

                const int FIR_SAMPLE = 65536;
                for (int offs=0; offs < pcm1ch.Length; offs += FIR_SAMPLE) {
                    int nSample = FIR_SAMPLE;
                    if (pcm1ch.Length < offs + nSample) {
                        nSample = pcm1ch.Length - offs;
                    }

                    var pcmFir = new double[nSample];
                    fir.Do(offs - window.Length / 2, nSample, pcmFir);

                    // 結果を出力に書き込む。
                    for (long i=0; i < pcmFir.Length; ++i) {
                        var re = pcmFir[i];
                        pcmDataImaginary.SetSampleValueInDouble(ch, i + offs,
                            (float)(re));
                    }

                    // 進捗Update。
                    int percentage = (int)(
                        (100L * ch / pcmDataImaginary.NumChannels) +
                        (100L * (offs + 1) / pcm1ch.Length / pcmDataImaginary.NumChannels));
                    m_ASWorker.ReportProgress(percentage);
                }
                fir.Unsetup();
            }

            // 解析信号を出力。
            m_analyticSignalList.Clear();
            for (int ch=0; ch < pcmDataReal.NumChannels; ++ch) {
                double [] signal = new double[pcmDataImaginary.NumFrames * 2];
                for (long pos=0; pos < pcmDataReal.NumFrames; ++pos) {
                    signal[pos * 2 + 0] = pcmDataReal.GetSampleValueInDouble(ch, pos);
                    signal[pos * 2 + 1] = pcmDataImaginary.GetSampleValueInDouble(ch, pos);
                }
                m_analyticSignalList.Add(signal);
            }

            sw.Stop();
            e.Result = "";
        }
        private byte[] ConvI32toI24orI32V24(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;
                bool writePad = toFormat == WasapiCS.SampleFormatType.Sint32V24;

                switch (noiseShaping) {
                case NoiseShapingType.None: {
                        for (int i = 0; i < nSample; ++i) {
                            // discard lower 8-bit
                            if (writePad) {
                                to[toPos++] = 0;
                            }
                            to[toPos++] = from[fromPos + 1];
                            to[toPos++] = from[fromPos + 2];
                            to[toPos++] = from[fromPos + 3];

                            fromPos += 4;
                        }
                    }
                    break;
                case NoiseShapingType.AddDither: {
                        for (int i = 0; i < nSample; ++i) {
                            long v = (int)((from[fromPos + 0] << 0) + (from[fromPos + 1] << 8) + (from[fromPos + 2] << 16) + (from[fromPos + 3] << 24));

                            // TPDF dither (width 512, center 128, left edge -128, right edge 384)
                            int dither = (int)((mRand.NextDouble() + mRand.NextDouble() - 0.5) * 256);

                            v += dither;

                            int vOut;
                            if (Int32.MaxValue < v) {
                                vOut = Int32.MaxValue;
                            } else if (v < Int32.MinValue) {
                                vOut = Int32.MinValue;
                            } else {
                                vOut = (int)v;
                            }

                            if (writePad) {
                                to[toPos++] = 0;
                            }
                            to[toPos++] = (byte)((vOut >> 8) & 0xff);
                            to[toPos++] = (byte)((vOut >> 16) & 0xff);
                            to[toPos++] = (byte)((vOut >> 24) & 0xff);

                            fromPos += 4;
                        }
                        args.noiseShapingOrDitherPerformed = true;
                    }
                    break;
                case NoiseShapingType.NoiseShaping1stOrder: {
                        long nFrame = nSample / pcmFrom.NumChannels;
                        System.Diagnostics.Debug.Assert(mErr != null && mErr.Length == pcmFrom.NumChannels);

                        for (int i = 0; i < nFrame; ++i) {
                            for (int ch=0; ch < pcmFrom.NumChannels; ++ch) {
                                int v = (short)(from[fromPos + 1] + (from[fromPos + 2] << 8) + (from[fromPos + 3] << 16));

                                v += mErr[ch] >> 8;
                                if (8388607 < v) {
                                    v = 8388607;
                                }

                                mErr[ch] -= ((mErr[ch]) >> 8) << 8;
                                mErr[ch] += from[fromPos];

                                if (writePad) {
                                    to[toPos++] = 0;
                                }
                                to[toPos++] = (byte)(v & 0xff);
                                to[toPos++] = (byte)((v >> 8) & 0xff);
                                to[toPos++] = (byte)((v >> 16) & 0xff);

                                fromPos += 4;
                            }
                        }
                        args.noiseShapingOrDitherPerformed = true;
                    }
                    break;
                case NoiseShapingType.DitheredNoiseShaping1stOrder: {
                        long nFrame = nSample / pcmFrom.NumChannels;
                        System.Diagnostics.Debug.Assert(mErr != null && mErr.Length == pcmFrom.NumChannels);

                        for (int i = 0; i < nFrame; ++i) {
                            for (int ch=0; ch < pcmFrom.NumChannels; ++ch) {
                                long v = (int)((from[fromPos + 0] << 0) + (from[fromPos + 1] << 8) + (from[fromPos + 2] << 16) + (from[fromPos + 3] << 24));

                                // RPDF
                                int dither = (int)((mRand.NextDouble() - 0.5) * 256 / 4);

                                v += mErr[ch] + dither;

                                int vOut;
                                if (Int32.MaxValue < v) {
                                    vOut = Int32.MaxValue;
                                } else if (v < Int32.MinValue) {
                                    vOut = Int32.MinValue;
                                } else {
                                    vOut = (int)v;
                                }
                                vOut = (int)(vOut & 0xffffff00);

                                mErr[ch] = (int)(v - vOut);

                                if (writePad) {
                                    to[toPos++] = 0;
                                }
                                to[toPos++] = (byte)((vOut >> 8) & 0xff);
                                to[toPos++] = (byte)((vOut >> 16) & 0xff);
                                to[toPos++] = (byte)((vOut >> 24) & 0xff);

                                fromPos += 4;
                            }
                        }
                        args.noiseShapingOrDitherPerformed = true;
                    }
                    break;
                }
            });
        }
        private byte[] ConvI32toF32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;

                for (int i = 0; i < nSample; ++i) {
                    int iv = ((int)from[fromPos + 1] << 8)
                           + ((int)from[fromPos + 2] << 16)
                           + ((int)from[fromPos + 3] << 24);
                    float fv = ((float)iv) * (1.0f / 2147483648.0f);

                    byte [] b = System.BitConverter.GetBytes(fv);

                    to[toPos++] = b[0];
                    to[toPos++] = b[1];
                    to[toPos++] = b[2];
                    to[toPos++] = b[3];
                    fromPos += 4;
                }
            });
        }
        private byte[] ConvI24or32toI16(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;
                int fromBytesPerSample = pcmFrom.BitsPerSample / 8;

                switch (noiseShaping) {
                case NoiseShapingType.None: {
                        int fromSkipCount = 1;
                        if (pcmFrom.BitsPerSample == 32) {
                            fromSkipCount = 2;
                        }

                        for (int i = 0; i < nSample; ++i) {
                            // discard lower bits
                            fromPos += fromSkipCount;

                            to[toPos++] = from[fromPos++];
                            to[toPos++] = from[fromPos++];
                        }
                    }
                    break;
                case NoiseShapingType.AddDither: {
                        if (pcmFrom.BitsPerSample == 32) {
                            // discard lower 8-bit
                            ++fromPos;
                        }

                        for (int i = 0; i < nSample; ++i) {
                            long v = (int)((from[fromPos] << 8) + (from[fromPos + 1] << 16) + (from[fromPos + 2] << 24));

                            // TPDF dither (width 131072, center 32768, left edge -32768, right edge 98304)
                            int dither = (int)((mRand.NextDouble() + mRand.NextDouble() - 0.5) * 65536);

                            v += dither;

                            int vOut;
                            if (Int32.MaxValue < v) {
                                vOut = Int32.MaxValue;
                            } else if (v < Int32.MinValue) {
                                vOut = Int32.MinValue;
                            } else {
                                vOut = (int)v;
                            }

                            to[toPos++] = (byte)((vOut >> 16) & 0xff);
                            to[toPos++] = (byte)((vOut >> 24) & 0xff);

                            fromPos += fromBytesPerSample;
                        }
                        args.noiseShapingOrDitherPerformed = true;
                    }
                    break;
                case NoiseShapingType.NoiseShaping1stOrder: {
                        long nFrame = nSample / pcmFrom.NumChannels;
                        System.Diagnostics.Debug.Assert(mErr != null && mErr.Length == pcmFrom.NumChannels);

                        if (pcmFrom.BitsPerSample == 32) {
                            // discard lower 8-bit
                            ++fromPos;
                        }

                        for (int i = 0; i < nFrame; ++i) {
                            for (int ch=0; ch < pcmFrom.NumChannels; ++ch) {
                                int v = (short)(from[fromPos + 1] + (from[fromPos + 2] << 8));

                                v += mErr[ch] >> 8;
                                if (32767 < v) {
                                    v = 32767;
                                }

                                mErr[ch] -= ((mErr[ch]) >> 8) << 8;
                                mErr[ch] += from[fromPos];

                                to[toPos++] = (byte)(v & 0xff);
                                to[toPos++] = (byte)((v >> 8) & 0xff);

                                fromPos += fromBytesPerSample;
                            }
                        }
                        args.noiseShapingOrDitherPerformed = true;
                    }
                    break;
                case NoiseShapingType.DitheredNoiseShaping1stOrder: {
                        long nFrame = nSample / pcmFrom.NumChannels;
                        System.Diagnostics.Debug.Assert(mErr != null && mErr.Length == pcmFrom.NumChannels);

                        if (pcmFrom.BitsPerSample == 32) {
                            // discard lower 8-bit
                            ++fromPos;
                        }

                        for (int i = 0; i < nFrame; ++i) {
                            for (int ch=0; ch < pcmFrom.NumChannels; ++ch) {
                                long v = (int)((from[fromPos] << 8) + (from[fromPos + 1] << 16) + (from[fromPos + 2] << 24));

                                // RPDF
                                int dither = (int)((mRand.NextDouble() - 0.5) * 65536 / 4);

                                v += mErr[ch] + dither;

                                int vOut;
                                if (Int32.MaxValue < v) {
                                    vOut = Int32.MaxValue;
                                } else if (v < Int32.MinValue) {
                                    vOut = Int32.MinValue;
                                } else {
                                    vOut = (int)v;
                                }
                                vOut = (int)(vOut & 0xffff0000);

                                mErr[ch] = (int)(v - vOut);

                                to[toPos++] = (byte)((vOut >> 16) & 0xff);
                                to[toPos++] = (byte)((vOut >> 24) & 0xff);

                                fromPos += fromBytesPerSample;
                            }
                        }
                        args.noiseShapingOrDitherPerformed = true;
                    }
                    break;
                }
            });
        }
        private byte[] ConvI16toF32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;

                for (int i = 0; i < nSample; ++i) {
                    short iv = (short)(from[fromPos]
                        + (from[fromPos + 1] << 8));
                    float fv = ((float)iv) * (1.0f / 32768.0f);

                    byte [] b = System.BitConverter.GetBytes(fv);

                    to[toPos++] = b[0];
                    to[toPos++] = b[1];
                    to[toPos++] = b[2];
                    to[toPos++] = b[3];
                    fromPos += 2;
                }
            });
        }
        private byte[] ConvF64toI24orI32V24(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;
                bool writePad = toFormat == WasapiCS.SampleFormatType.Sint32V24;

                for (int i = 0; i < nSample; ++i) {
                    double dv = System.BitConverter.ToDouble(from, fromPos);
                    if (SAMPLE_VALUE_MAX_DOUBLE <= dv) {
                        dv = SAMPLE_VALUE_MAX_DOUBLE_TO_I24;
                        IncrementClippedCounter();
                    }
                    if (dv < SAMPLE_VALUE_MIN_DOUBLE) {
                        dv = SAMPLE_VALUE_MIN_DOUBLE;
                        IncrementClippedCounter();
                    }
                    int iv = (int)(dv * 8388608.0);

                    if (writePad) {
                        to[toPos++] = 0;
                    }
                    to[toPos++] = (byte)(iv & 0xff);
                    to[toPos++] = (byte)((iv >> 8) & 0xff);
                    to[toPos++] = (byte)((iv >> 16) & 0xff);
                    fromPos += 8;
                }
            });
        }
Пример #16
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 &&
                pcmData.BitsPerSample != 64)
            {
                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;
                }

                pcmData.TrackId = mPlaylistTrackMeta.trackId;
            }

            bool readSeparatorAfter = false;

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

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

            mAddPcmData(pcmData, readSeparatorAfter, mPlis != null);
            return(true);
        }
Пример #17
0
 public void Insert(int idx, PcmData pd)
 {
     mPcmDataList.Insert(idx, pd);
 }
Пример #18
0
 public void Add(PcmData pd)
 {
     mPcmDataList.Add(pd);
 }
Пример #19
0
        /// <summary>
        /// 読み込み処理を通常終了する。
        /// </summary>
        /// <returns>Error code</returns>
        public int StreamEnd()
        {
            int rv = 0;

            mMD5SumInMetadata = null;
            mMD5SumOfPcm = null;

            switch (m_format) {
            case Format.FLAC:
                rv = mFlacR.ReadStreamEnd();
                mMD5SumInMetadata = mFlacR.MD5SumInMetadata;
                mMD5SumOfPcm = mFlacR.MD5SumOfPcm;
                break;
            case Format.AIFF:
                mAiffR.ReadStreamEnd();
                break;
            case Format.WAVE:
                mWaveR.ReadStreamEnd();
                break;
            case Format.DSF:
                mDsfR.ReadStreamEnd();
                break;
            case Format.DSDIFF:
                mDsdiffR.ReadStreamEnd();
                break;
            default:
                System.Diagnostics.Debug.Assert(false);
                break;
            }

            if (null != mBr) {
                mBr.Close();
                mBr = null;
            }
            mPcmData = null;
            mFlacR = null;
            mAiffR = null;
            mWaveR = null;
            mDsfR = null;

            return rv;
        }
Пример #20
0
        private void m_USAQworker_DoWork(object sender, DoWorkEventArgs e)
        {
            // System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Lowest;

            USWorkerArgs args = (USWorkerArgs)e.Argument;

            PcmData pcmDataIn = ReadWavFile(args.inputPath);
            if (null == pcmDataIn) {
                e.Result = string.Format("WAVファイル 読み込み失敗: {0}", args.inputPath);
                return;
            }

            // ファイル読み込み完了。
            if (args.addJitter) {
                // ジッター負荷の場合、サンプリング周波数は変更しない。
                args.resampleFrequency = pcmDataIn.SampleRate;
            }

            if (args.resampleFrequency < pcmDataIn.SampleRate) {
                e.Result = string.Format("エラー: ダウンサンプルは対応していません {0} from={1} to={2}",
                    args.inputPath, pcmDataIn.SampleRate, args.resampleFrequency);
                return;
            }
            if (0x7fff0000L < pcmDataIn.NumFrames * 4 * pcmDataIn.NumChannels * args.resampleFrequency / pcmDataIn.SampleRate) {
                e.Result = string.Format("エラー: リサンプル後のファイルサイズが2GBを超えそうなので中断しました {0}",
                    args.inputPath);
                return;
            }

            m_USAQworker.ReportProgress(1);

            var conv = new WasapiPcmUtil.PcmFormatConverter(pcmDataIn.NumChannels);
            pcmDataIn = conv.Convert(pcmDataIn, WasapiCS.BitAndFormatToSampleFormatType(32, 32, WasapiCS.BitFormatType.SFloat), null);
            PcmData pcmDataOut = new PcmData();
            pcmDataOut.CopyFrom(pcmDataIn);
            int sampleTotalTo = (int)(args.resampleFrequency * pcmDataIn.NumFrames / pcmDataIn.SampleRate);
            {   // PcmDataOutのサンプルレートとサンプル数を更新する。
                byte[] outSampleArray = new byte[(long)sampleTotalTo * pcmDataOut.NumChannels * 4];
                pcmDataOut.SetSampleArray(sampleTotalTo, outSampleArray);
                pcmDataOut.SampleRate = args.resampleFrequency;
                outSampleArray = null;
            }

            // 再サンプルテーブル作成
            args.resamplePosArray = null;
            args.fractionArray = null;
            if (args.addJitter) {
                // ジッター付加の場合、サンプルレートは変更しない。
                args.resamplePosArray = new int[pcmDataIn.NumFrames];
                args.fractionArray = new double[pcmDataIn.NumFrames];
                /*
                 sampleRate        == 96000 Hz
                 jitterFrequency   == 50 Hz
                 jitterPicoseconds == 1 ps の場合

                 サンプル位置posのθ= 2 * PI * pos * 50 / 96000 (ラジアン)

                 サンプル間隔= 1/96000秒 = 10.4 μs

                 1ms = 10^-3秒
                 1μs= 10^-6秒
                 1ns = 10^-9秒
                 1ps = 10^-12秒

                  1psのずれ                     x サンプルのずれ
                 ───────────── = ─────────
                  10.4 μs(1/96000)sのずれ      1 サンプルのずれ

                 1psのサンプルずれA = 10^-12 ÷ (1/96000) (サンプルのずれ)

                 サンプルを採取する位置= pos + Asin(θ)

                 */

                args.thetaCoefficientSeqJitter = 2.0 * Math.PI * args.sequentialJitterFrequency / pcmDataIn.SampleRate;
                args.ampSeqJitter = 1.0e-12 * pcmDataIn.SampleRate * args.sequentialJitterPicoseconds;
                args.ampTpdfJitter = 1.0e-12 * pcmDataIn.SampleRate * args.tpdfJitterPicoseconds;
                args.ampRpdfJitter = 1.0e-12 * pcmDataIn.SampleRate * args.rpdfJitterPicoseconds;

                PrepareResamplePosArray(
                    args, pcmDataIn.SampleRate, pcmDataOut.SampleRate,
                    (int)pcmDataIn.NumFrames, sampleTotalTo,
                    args.resamplePosArray, args.fractionArray);
            }

            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();

            int hr = 0;
            if (args.device == ProcessDevice.Gpu) {
                hr = GpuUpsample(args, pcmDataIn, pcmDataOut);
            } else {
                hr = CpuUpsample(args, pcmDataIn, pcmDataOut);
            }

            // args.resamplePosArrayは中でコピーされるのでここで不要になる。
            args.resamplePosArray = null;
            args.fractionArray = null;

            if (m_USAQworker.CancellationPending) {
                e.Result = string.Format("キャンセル完了。");
                e.Cancel = true;
                return;
            }
            if (hr < 0) {
                e.Result = string.Format("Upsample エラー 0x{0:X8}", hr);
                return;
            }
            sw.Stop();

            // 成功した。レベル制限する。
            float scale = pcmDataOut.LimitLevelOnFloatRange();

            if (args.outputVRT != PcmData.ValueRepresentationType.SFloat) {
                // ビットフォーマット変更。
                var formatConv = new WasapiPcmUtil.PcmFormatConverter(pcmDataOut.NumChannels);
                pcmDataOut = formatConv.Convert(pcmDataOut,
                        WasapiCS.BitAndFormatToSampleFormatType(args.outputBitsPerSample, args.outputBitsPerSample, (WasapiCS.BitFormatType)args.outputVRT), null);
            }

            try {
                WriteWavFile(pcmDataOut, args.outputPath);
            } catch (IOException ex) {
                // 書き込みエラー。
                e.Result = ex.ToString();
                return;
            }

            e.Result = string.Format("書き込み成功。処理時間 {0}秒\r\n",
                sw.ElapsedMilliseconds * 0.001);
            if (scale < 1.0f) {
                e.Result = string.Format("書き込み成功。処理時間 {0}秒。" +
                    "レベルオーバーのため音量調整{1}dB({2}倍)しました。\r\n",
                    sw.ElapsedMilliseconds * 0.001,
                    20.0 * Math.Log10(scale), scale);
            }
            m_USAQworker.ReportProgress(100);
        }
        private byte[] ConvI32V24toI32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;

                for (int i = 0; i < nSample; ++i) {
                    // discard lower 8-bit because it is garbage
                    to[toPos++] = 0;
                    to[toPos++] = from[fromPos + 1];
                    to[toPos++] = from[fromPos + 2];
                    to[toPos++] = from[fromPos + 3];

                    fromPos += 4;
                }
            });
        }
Пример #22
0
        public void StreamAbort()
        {
            switch (m_format) {
            case Format.FLAC:
                mFlacR.ReadStreamAbort();
                break;
            case Format.AIFF:
                mAiffR.ReadStreamEnd();
                break;
            case Format.WAVE:
                mWaveR.ReadStreamEnd();
                break;
            case Format.DSF:
                mDsfR.ReadStreamEnd();
                break;
            case Format.DSDIFF:
                mDsdiffR.ReadStreamEnd();
                break;
            default:
                System.Diagnostics.Debug.Assert(false);
                break;
            }

            if (null != mBr) {
                mBr.Close();
                mBr = null;
            }
            mPcmData = null;
            mFlacR = null;
            mAiffR = null;
            mWaveR = null;
            mDsfR = null;
        }
        /// <summary>
        /// Converts sample format to toFormat and returns new instance of PcmData.
        /// pcmFrom is not changed.
        /// </summary>
        /// <param name="toFormat">sample format to convert</param>
        /// <returns>Newly instanciated PcmData</returns>
        public PcmData Convert(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            if (args == null) {
                args = new BitsPerSampleConvArgs(NoiseShapingType.None);
            }

            var fromFormat = WasapiCS.BitAndFormatToSampleFormatType(pcmFrom.BitsPerSample, pcmFrom.ValidBitsPerSample,
                    SampleFormatInfo.VrtToBft(pcmFrom.SampleValueRepresentationType));

            if (fromFormat == WasapiCS.SampleFormatType.Unknown ||
                    toFormat == WasapiCS.SampleFormatType.Unknown) {
                return null;
            }

            var newSampleArray = mConvert[(int)fromFormat][(int)toFormat](pcmFrom, toFormat, args);

            PcmData newPcmData = new PcmData();
            newPcmData.CopyHeaderInfoFrom(pcmFrom);
            newPcmData.SetFormat(pcmFrom.NumChannels,
                    WasapiCS.SampleFormatTypeToUseBitsPerSample(toFormat),
                    WasapiCS.SampleFormatTypeToValidBitsPerSample(toFormat), pcmFrom.SampleRate,
                    SampleFormatInfo.BftToVrt(WasapiCS.SampleFormatTypeToBitFormatType(toFormat)), pcmFrom.NumFrames);
            newPcmData.SetSampleArray(newSampleArray);

            return newPcmData;
        }
        private byte[] ConvF64toI32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;

                for (int i = 0; i < nSample; ++i) {
                    double dv = System.BitConverter.ToDouble(from, fromPos);

                    int iv = 0;
                    if ((long)Int32.MaxValue < (long)(dv * Int32.MaxValue)) {
                        iv = Int32.MaxValue;
                        IncrementClippedCounter();
                    } else if ((long)(-dv * Int32.MinValue) < (long)Int32.MinValue) {
                        iv = Int32.MinValue;
                        IncrementClippedCounter();
                    } else {
                        iv = (int)(-dv * Int32.MinValue);
                    }

                    to[toPos++] = (byte)((iv >> 0) & 0xff);
                    to[toPos++] = (byte)((iv >> 8) & 0xff);
                    to[toPos++] = (byte)((iv >> 16) & 0xff);
                    to[toPos++] = (byte)((iv >> 24) & 0xff);
                    fromPos += 8;
                }
            });
        }
 private byte[] ConvClone(PcmData from, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
 {
     return (byte[])from.GetSampleArray().Clone();
 }
        private byte[] ConvI16toF64(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;

                for (int i = 0; i < nSample; ++i) {
                    short iv = (short)(from[fromPos]
                        + (from[fromPos + 1] << 8));
                    double dv = ((double)iv) * (1.0 / 32768.0);

                    byte [] b = System.BitConverter.GetBytes(dv);

                    for (int j=0; j < 8; ++j) {
                        to[toPos++] = b[j];
                    }
                    fromPos += 2;
                }
            });
        }
 private byte[] ConvCommon(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args, ConversionLoop convLoop)
 {
     var from = pcmFrom.GetSampleArray();
     long nSample = from.LongLength * 8 / pcmFrom.BitsPerSample;
     var to = new byte[nSample * WasapiCS.SampleFormatTypeToUseBitsPerSample(toFormat) / 8];
     convLoop(from, to, nSample, args.noiseShaping);
     return to;
 }
        private byte[] ConvI24toI32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;

                for (int i = 0; i < nSample; ++i) {
                    // Lower 8-bit: fill 0s
                    to[toPos++] = 0;

                    // Higher 24-bit: copy PCM
                    to[toPos++] = from[fromPos++];
                    to[toPos++] = from[fromPos++];
                    to[toPos++] = from[fromPos++];
                }
            });
        }
 private byte[] ConvError(PcmData from, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
 {
     System.Diagnostics.Debug.Assert(false);
     return null;
 }
        private byte[] ConvI32toF64(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;

                for (int i = 0; i < nSample; ++i) {
                    int iv = ((int)from[fromPos + 1] << 8)
                           + ((int)from[fromPos + 2] << 16)
                           + ((int)from[fromPos + 3] << 24);
                    double dv = ((double)iv) * (1.0 / 2147483648.0);

                    byte [] b = System.BitConverter.GetBytes(dv);

                    for (int j=0; j < 8; ++j) {
                        to[toPos++] = b[j];
                    }
                    fromPos += 4;
                }
            });
        }
Пример #31
0
 /// <summary>
 /// サンプリング周波数と量子化ビット数、有効なビット数、チャンネル数、データ形式が同じならtrue
 /// </summary>
 public bool IsSameFormat(PcmData other)
 {
     return BitsPerSample      == other.BitsPerSample
         && ValidBitsPerSample == other.ValidBitsPerSample
         && SampleRate    == other.SampleRate
         && NumChannels   == other.NumChannels
         && SampleValueRepresentationType == other.SampleValueRepresentationType
         && SampleDataType == other.SampleDataType;
 }
        private byte[] ConvI32V24toI24(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;

                for (int i = 0; i < nSample; ++i) {
                    // truncate lower 8-bit of 32-bit PCM to create 24-bit PCM
                    to[toPos++] = from[fromPos + 1];
                    to[toPos++] = from[fromPos + 2];
                    to[toPos++] = from[fromPos + 3];

                    fromPos += 4;
                }
            });
        }
        private byte[] ConvF32toI16(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;

                switch (noiseShaping) {
                case NoiseShapingType.None:
                    for (int i = 0; i < nSample; ++i) {
                        float fv = System.BitConverter.ToSingle(from, fromPos);
                        if (SAMPLE_VALUE_MAX_FLOAT <= fv) {
                            fv = SAMPLE_VALUE_MAX_FLOAT_TO_I16;
                            IncrementClippedCounter();
                        }
                        if (fv < SAMPLE_VALUE_MIN_FLOAT) {
                            fv = SAMPLE_VALUE_MIN_FLOAT;
                            IncrementClippedCounter();
                        }

                        int iv = (int)(fv * 32768.0f);

                        to[toPos++] = (byte)(iv & 0xff);
                        to[toPos++] = (byte)((iv >> 8) & 0xff);
                        fromPos += 4;
                    }
                    break;
                case NoiseShapingType.AddDither: {
                        for (int i = 0; i < nSample; ++i) {
                            float fv = System.BitConverter.ToSingle(from, fromPos);
                            if (SAMPLE_VALUE_MAX_FLOAT <= fv) {
                                fv = SAMPLE_VALUE_MAX_FLOAT_TO_I16;
                                IncrementClippedCounter();
                            }
                            if (fv < SAMPLE_VALUE_MIN_FLOAT) {
                                fv = SAMPLE_VALUE_MIN_FLOAT;
                                IncrementClippedCounter();
                            }

                            long iv = (long)(fv * Int32.MaxValue);

                            // TPDF
                            int dither = (int)((mRand.NextDouble() + mRand.NextDouble() - 0.5) * 65536);

                            iv += dither;

                            int vOut;
                            if (Int32.MaxValue < iv) {
                                vOut = Int32.MaxValue;
                            } else if (iv < Int32.MinValue) {
                                vOut = Int32.MinValue;
                            } else {
                                vOut = (int)iv;
                            }

                            to[toPos++] = (byte)((vOut >> 16) & 0xff);
                            to[toPos++] = (byte)((vOut >> 24) & 0xff);
                            fromPos += 4;
                        }
                        args.noiseShapingOrDitherPerformed = true;
                    }
                    break;
                case NoiseShapingType.NoiseShaping1stOrder: {
                        long nFrame = nSample / pcmFrom.NumChannels;
                        System.Diagnostics.Debug.Assert(mErr != null && mErr.Length == pcmFrom.NumChannels);

                        for (int i = 0; i < nFrame; ++i) {
                            for (int ch=0; ch < pcmFrom.NumChannels; ++ch) {
                                float fv = System.BitConverter.ToSingle(from, fromPos);
                                if (SAMPLE_VALUE_MAX_FLOAT <= fv) {
                                    fv = SAMPLE_VALUE_MAX_FLOAT_TO_I16;
                                    IncrementClippedCounter();
                                }
                                if (fv < SAMPLE_VALUE_MIN_FLOAT) {
                                    fv = SAMPLE_VALUE_MIN_FLOAT;
                                    IncrementClippedCounter();
                                }
                                long lv = (long)((double)fv * ((long)Int32.MaxValue + 1L) + mErr[ch]);

                                int iv;
                                if (Int32.MaxValue < lv) {
                                    iv = Int32.MaxValue;
                                } else if (lv < Int32.MinValue) {
                                    iv = Int32.MinValue;
                                } else {
                                    iv = (int)lv;
                                }

                                iv = (int)(iv & 0xffff0000);
                                mErr[ch] = (int)(lv - iv);

                                to[toPos++] = (byte)((iv >> 16) & 0xff);
                                to[toPos++] = (byte)((iv >> 24) & 0xff);
                                fromPos += 4;
                            }
                        }
                        args.noiseShapingOrDitherPerformed = true;
                    }
                    break;
                case NoiseShapingType.DitheredNoiseShaping1stOrder: {
                        long nFrame = nSample / pcmFrom.NumChannels;
                        System.Diagnostics.Debug.Assert(mErr != null && mErr.Length == pcmFrom.NumChannels);

                        for (int i = 0; i < nFrame; ++i) {
                            for (int ch=0; ch < pcmFrom.NumChannels; ++ch) {
                                float fv = System.BitConverter.ToSingle(from, fromPos);
                                if (SAMPLE_VALUE_MAX_FLOAT <= fv) {
                                    fv = SAMPLE_VALUE_MAX_FLOAT_TO_I16;
                                    IncrementClippedCounter();
                                }
                                if (fv < SAMPLE_VALUE_MIN_FLOAT) {
                                    fv = SAMPLE_VALUE_MIN_FLOAT;
                                    IncrementClippedCounter();
                                }

                                // RPDF
                                double dither = (mRand.NextDouble() - 0.5) * 65536 / 4;

                                long lv = (long)((double)fv * ((long)Int32.MaxValue + 1L) + mErr[ch] + dither);

                                int iv;
                                if (Int32.MaxValue < lv) {
                                    iv = Int32.MaxValue;
                                } else if (lv < Int32.MinValue) {
                                    iv = Int32.MinValue;
                                } else {
                                    iv = (int)lv;
                                }

                                iv = (int)(iv & 0xffff0000);
                                mErr[ch] = (int)(lv - iv);

                                to[toPos++] = (byte)((iv >> 16) & 0xff);
                                to[toPos++] = (byte)((iv >> 24) & 0xff);

                                fromPos += 4;
                            }
                        }
                        args.noiseShapingOrDitherPerformed = true;
                    }
                    break;
                }
            });
        }
Пример #34
0
        public PcmData ConvertChannelCount(int newCh)
        {
            if (NumChannels == newCh)
            {
                // 既に希望のチャンネル数である。
                return(this);
            }

            // サンプルあたりビット数が8の倍数でないとこのアルゴリズムは使えない
            System.Diagnostics.Debug.Assert((BitsPerSample & 7) == 0);

            // 新しいサンプルサイズ
            // NumFramesは総フレーム数。sampleArrayのフレーム数はこれよりも少ないことがある。
            // 実際に存在するサンプル数sampleFramesだけ処理する。
            int  bytesPerSample = BitsPerSample / 8;
            long sampleFrames   = mSampleLargeArray.LongLength / (BitsPerFrame / 8);
            var  newSampleArray = new WWUtil.LargeArray <byte>((long)newCh * bytesPerSample * sampleFrames);

            for (long frame = 0; frame < sampleFrames; ++frame)
            {
                int copyBytes = NumChannels * bytesPerSample;
                if (newCh < NumChannels)
                {
                    // チャンネル数が減る場合。
                    copyBytes = newCh * bytesPerSample;
                }

                newSampleArray.CopyFrom(mSampleLargeArray, (long)NumChannels * bytesPerSample * frame,
                                        (long)newCh * bytesPerSample * frame, copyBytes);

                if (SampleDataType == DataType.DoP &&
                    NumChannels < newCh)
                {
                    // 追加したチャンネルにDSD無音をセットする。
                    switch (bytesPerSample)
                    {
                    case 3:
                        for (int ch = NumChannels; ch < newCh; ++ch)
                        {
                            newSampleArray.Set((frame * newCh + ch) * bytesPerSample + 0, 0x69);
                            newSampleArray.Set((frame * newCh + ch) * bytesPerSample + 1, 0x69);
                            newSampleArray.Set((frame * newCh + ch) * bytesPerSample + 2, (byte)((frame & 1) == 1 ? 0xfa : 0x05));
                        }
                        break;

                    case 4:
                        for (int ch = NumChannels; ch < newCh; ++ch)
                        {
                            newSampleArray.Set((frame * newCh + ch) * bytesPerSample + 1, 0x69);
                            newSampleArray.Set((frame * newCh + ch) * bytesPerSample + 2, 0x69);
                            newSampleArray.Set((frame * newCh + ch) * bytesPerSample + 3, (byte)((frame & 1) == 1 ? 0xfa : 0x05));
                        }
                        break;
                    }
                }
            }

            PcmData newPcmData = new PcmData();

            newPcmData.CopyHeaderInfoFrom(this);
            newPcmData.SetFormat(newCh, BitsPerSample, ValidBitsPerSample, SampleRate, SampleValueRepresentationType, NumFrames);
            newPcmData.SetSampleLargeArray(newSampleArray);

            return(newPcmData);
        }
        private byte[] ConvF32toI32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;

                for (int i = 0; i < nSample; ++i) {
                    float fv = System.BitConverter.ToSingle(from, fromPos);
                    if (SAMPLE_VALUE_MAX_FLOAT <= fv) {
                        fv = SAMPLE_VALUE_MAX_FLOAT_TO_I24;
                        IncrementClippedCounter();
                    }
                    if (fv < SAMPLE_VALUE_MIN_FLOAT) {
                        fv = SAMPLE_VALUE_MIN_FLOAT;
                        IncrementClippedCounter();
                    }
                    int iv = (int)(fv * 8388608.0f);

                    to[toPos++] = 0;
                    to[toPos++] = (byte)(iv & 0xff);
                    to[toPos++] = (byte)((iv >> 8) & 0xff);
                    to[toPos++] = (byte)((iv >> 16) & 0xff);
                    fromPos += 4;
                }
            });
        }
Пример #36
0
        /// <summary>
        /// ヘッダー情報、サンプルデータ領域をクローンする。
        /// </summary>
        public void CopyFrom(PcmData rhs)
        {
            CopyHeaderInfoFrom(rhs);

            mSampleArray = null;
            if (rhs.mSampleArray != null) {
                mSampleArray = (byte[])rhs.mSampleArray.Clone();
            }
        }
        private byte[] ConvF64toF32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;

                for (int i = 0; i < nSample; ++i) {
                    double dv = System.BitConverter.ToDouble(from, fromPos);
                    float fv = (float)dv;
                    if (SAMPLE_VALUE_MAX_FLOAT <= fv) {
                        fv = SAMPLE_VALUE_MAX_FLOAT_TO_I24;
                        IncrementClippedCounter();
                    }
                    if (fv < SAMPLE_VALUE_MIN_FLOAT) {
                        fv = SAMPLE_VALUE_MIN_FLOAT;
                        IncrementClippedCounter();
                    }
                    byte [] b = System.BitConverter.GetBytes(fv);
                    to[toPos++] = b[0];
                    to[toPos++] = b[1];
                    to[toPos++] = b[2];
                    to[toPos++] = b[3];
                    fromPos += 8;
                }
            });
        }
        private byte[] ConvF32toF64(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args)
        {
            return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => {
                int fromPos = 0;
                int toPos   = 0;

                for (int i = 0; i < nSample; ++i) {
                    float fv = System.BitConverter.ToSingle(from, fromPos);
                    double dv = (double)fv;

                    byte [] b = System.BitConverter.GetBytes(dv);
                    for (int j=0; j < 8; ++j) {
                        to[toPos++] = b[j];
                    }
                    fromPos += 4;
                }
            });
        }
Пример #39
0
        public PcmData MonoToStereo()
        {
            System.Diagnostics.Debug.Assert(NumChannels == 1);

            // サンプルあたりビット数が8の倍数でないとこのアルゴリズムは使えない
            System.Diagnostics.Debug.Assert((BitsPerSample & 7) == 0);

            byte [] newSampleArray = new byte[mSampleArray.LongLength * 2];

            {
                int bytesPerSample = BitsPerSample / 8;

                // NumFramesは総フレーム数。sampleArrayのフレーム数はこれよりも少ないことがある。
                // 実際に存在するサンプル数sampleFramesだけ処理する。
                long sampleFrames = mSampleArray.LongLength / bytesPerSample;
                long fromPosBytes = 0;
                for (long frame = 0; frame < sampleFrames; ++frame) {
                    for (int offs = 0; offs < bytesPerSample; ++offs) {
                        newSampleArray[fromPosBytes * 2 + offs] = mSampleArray[fromPosBytes + offs];
                        newSampleArray[fromPosBytes * 2 + bytesPerSample + offs] = mSampleArray[fromPosBytes + offs];
                    }
                    fromPosBytes += bytesPerSample;
                }
            }
            PcmData newPcmData = new PcmData();
            newPcmData.CopyHeaderInfoFrom(this);
            newPcmData.SetFormat(2, BitsPerSample, ValidBitsPerSample, SampleRate, SampleValueRepresentationType, NumFrames);
            newPcmData.SetSampleArray(newSampleArray);

            return newPcmData;
        }