private static void AssembleSample(List <WWUtil.LargeArray <double> > dataList, long count,
                                           out WWUtil.LargeArray <double> gathered, out WWUtil.LargeArray <double> remainings)
        {
            gathered = new WWUtil.LargeArray <double>(count);

            // この関数が呼び出されるときにはdataListにはcountバイト丁度か、
            // countバイトよりも少し多いバイト数を含んでいて配列の個数は丁度必要な数入っている。
            // もしも余剰バイトがあるときはそれは最後の配列に含まれる。

            long offs         = 0;
            long remainLength = 0;

            foreach (var d in dataList)
            {
                long length = d.LongLength;
                remainLength = 0;
                if (count < offs + length)
                {
                    length       = count - offs;
                    remainLength = d.LongLength - length;
                }

                gathered.CopyFrom(d, 0, offs, length);
                offs += length;
            }

            remainings = new WWUtil.LargeArray <double>(remainLength);
            if (0 < remainLength)
            {
                long lastDataLength = dataList[dataList.Count - 1].LongLength;
                remainings.CopyFrom(dataList[dataList.Count - 1], lastDataLength - remainLength, 0, remainLength);
            }
        }
        /// <summary>
        /// double型のLargeArrayを戻すバージョン。
        /// </summary>
        /// <param name="longCount">取得する要素数。範囲外の領域は0が入る。</param>
        /// <returns></returns>
        public WWUtil.LargeArray <double> GetPcmInDoublePcm(long longCount)
        {
            // 確保するサイズはlongCount個。
            var result = new WWUtil.LargeArray <double>(longCount);

            long fromPos = mOffsBytes / (mBitsPerSample / 8);
            long toPos   = 0;

            // コピーするデータの個数はcount個よりも少ないことがある。
            long copyCount = result.LongLength;

            if (mTotalSamples < fromPos + copyCount)
            {
                copyCount = (int)(mTotalSamples - fromPos);
            }

            for (long remain = copyCount; 0 < remain;)
            {
                int fragmentCount = WWUtil.LargeArray <byte> .ARRAY_FRAGMENT_LENGTH_NUM;
                if (remain < fragmentCount)
                {
                    fragmentCount = (int)remain;
                }

                var fragment = GetPcmInDoublePcm(fragmentCount);
                result.CopyFrom(fragment, 0, toPos, fragmentCount);
                fragment = null;

                toPos  += fragmentCount;
                remain -= fragmentCount;
            }

            return(result);
        }
Exemple #3
0
        /// <summary>
        /// double サンプル値セット。フォーマットが64bit SFloatの場合のみ使用可能。
        /// </summary>
        public void SetSampleValueInDouble(int ch, long pos, double val)
        {
            Debug.Assert(SampleValueRepresentationType == ValueRepresentationType.SFloat);
            Debug.Assert(ValidBitsPerSample == 64);
            Debug.Assert(0 <= ch && ch < NumChannels);

            if (pos < 0 || NumFrames <= pos)
            {
                return;
            }

            long offset = pos * BitsPerFrame / 8 + ch * BitsPerSample / 8;

            var byteArray = BitConverter.GetBytes(val);

            mSampleLargeArray.CopyFrom(byteArray, 0, offset, 8);
        }
        public WWUtil.LargeArray <double> GetPcmInDoubleSdm1bit(long longCount)
        {
            // サンプル数 / 8 == バイト数。
            var result = new WWUtil.LargeArray <double>(longCount);

            if (mTotalSamples / 8 <= mOffsBytes || longCount == 0)
            {
                // 完全に範囲外の時。
                int writePos = 0;
                for (long i = 0; i < (longCount + 7) / 8; ++i)
                {
                    byte b = 0x69; // DSD silence

                    // 1バイト内のビットの並びはMSBから古い順にデータが詰まっている。
                    for (int bit = 7; 0 <= bit; --bit)
                    {
                        if (longCount <= writePos)
                        {
                            break;
                        }
                        result.Set(writePos++, ((b >> bit) & 1) == 1 ? 1.0 : -1.0);
                    }
                }

                return(result);
            }
            else
            {
                long copySamples = longCount;
                if (mTotalSamples < mOffsBytes * 8 + copySamples)
                {
                    copySamples = mTotalSamples - mOffsBytes * 8;
                }

                long toPos = 0;
                for (long remain = copySamples; 0 < remain;)
                {
                    int fragmentCount = WWUtil.LargeArray <byte> .ARRAY_FRAGMENT_LENGTH_NUM;
                    if (remain < fragmentCount)
                    {
                        fragmentCount = (int)remain;
                    }

                    var fragment = GetPcmInDoubleSdm1bit(fragmentCount);
                    result.CopyFrom(fragment, 0, toPos, fragmentCount);
                    fragment = null;

                    toPos  += fragmentCount;
                    remain -= fragmentCount;
                }

                return(result);
            }
        }
        public virtual WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcm)
        {
            long num = NumOfSamplesNeeded();

            if (inPcm.LongLength != num)
            {
                throw new ArgumentOutOfRangeException("inPcm");
            }

            WWUtil.LargeArray <double> outPcm = new WWUtil.LargeArray <double>(num);
            outPcm.CopyFrom(inPcm, 0, 0, num);
            return(outPcm);
        }
Exemple #6
0
        private void TrimInternal(long startFrame, long endFrame)
        {
            if (startFrame == 0 && endFrame < 0)
            {
                // データTrimの必要はない。
                return;
            }

            if (endFrame < 0 ||
                NumFrames < endFrame)
            {
                // 終了位置はファイルの終わり。
                endFrame = NumFrames;
            }

            if (endFrame < startFrame)
            {
                // 1サンプルもない。
                startFrame = endFrame;
            }

            long startBytes = startFrame * BitsPerFrame / 8;
            long endBytes   = endFrame * BitsPerFrame / 8;

            Debug.Assert(0 <= startBytes);
            Debug.Assert(0 <= endBytes);
            Debug.Assert(startBytes <= endBytes);
            Debug.Assert(null != mSampleLargeArray);
            Debug.Assert(startBytes <= mSampleLargeArray.LongLength);
            Debug.Assert(endBytes <= mSampleLargeArray.LongLength);

            long newNumSamples = endFrame - startFrame;

            mNumFrames = newNumSamples;
            if (newNumSamples == 0 ||
                mSampleLargeArray.LongLength <= startBytes)
            {
                mSampleLargeArray = null;
                mNumFrames        = 0;
            }
            else
            {
                var newArray = new WWUtil.LargeArray <byte>(endBytes - startBytes);
                newArray.CopyFrom(mSampleLargeArray, startBytes, 0, endBytes - startBytes);
                mSampleLargeArray = null;
                mSampleLargeArray = newArray;
            }
        }
Exemple #7
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);
        }
        public static int ReadFlacFile(string path, out AudioData ad)
        {
            ad = new AudioData();

            var flac = new WWFlacRWCS.FlacRW();
            int rv   = flac.DecodeAll(path);

            if (rv < 0)
            {
                MessageBox.Show(
                    string.Format("Error: Failed to read FLAC file: {0}", path));
                return(rv);
            }

            rv = flac.GetDecodedMetadata(out ad.meta);
            if (rv < 0)
            {
                return(rv);
            }

            rv = flac.GetDecodedPicture(out ad.picture, ad.meta.pictureBytes);
            if (rv < 0)
            {
                return(rv);
            }

            // ad.pcmにPCMデータを入れる。

            int bpf             = ad.meta.BytesPerFrame;
            int bps             = ad.meta.BytesPerSample;
            int fragmentSamples = 4096;
            int fragmentBytes   = fragmentSamples * bps;
            var fragment        = new byte[fragmentBytes];

            ad.pcm = new List <AudioDataPerChannel>();
            for (int ch = 0; ch < ad.meta.channels; ++ch)
            {
                // ■■■ 1チャンネル分のpcmを取り出す。■■■

                long oneChannelPcmBytes = ad.meta.totalSamples * bps;
                var  pcm = new WWUtil.LargeArray <byte>(oneChannelPcmBytes);

                for (long posS = 0; posS < ad.meta.totalSamples;)
                {
                    // copySamples : コピーするサンプル数を決定する。
                    int copySamples = fragmentSamples;
                    if (ad.meta.totalSamples < posS + fragmentSamples)
                    {
                        copySamples = (int)(ad.meta.totalSamples - posS);
                    }

                    copySamples = flac.GetPcmOfChannel(ch, posS, ref fragment, copySamples);
                    if (copySamples < 0)
                    {
                        return(copySamples);
                    }

                    // fragmentに入っているPCMデータのサイズはcopySamples * bpsバイト。
                    pcm.CopyFrom(fragment, 0, posS * bps, copySamples * bps);
                    posS += copySamples;
                }

                var pcm24 = PcmDataLib.PcmDataUtil.ConvertTo24bit(ad.meta.bitsPerSample,
                                                                  ad.meta.totalSamples, PcmDataLib.PcmData.ValueRepresentationType.SInt, pcm);

                var adp = new AudioDataPerChannel();
                adp.mDataFormat              = AudioDataPerChannel.DataFormat.Pcm;
                adp.mData                    = pcm24;
                adp.mOffsBytes               = 0;
                adp.mBitsPerSample           = 24;
                adp.mValueRepresentationType = PcmDataLib.PcmData.ValueRepresentationType.SInt;
                adp.mTotalSamples            = ad.meta.totalSamples;
                ad.pcm.Add(adp);
            }

            // converted to 24bit
            ad.meta.bitsPerSample  = 24;
            ad.preferredSaveFormat = WWAFUtil.FileFormatType.FLAC;

            flac.DecodeEnd();

            return(0);
        }