/// <summary> /// 指定チャンネル番号のPCMデータを取り出す。 /// DecodeAll()後に呼ぶ。 /// </summary> /// <param name="copySamples">バイト換算で512MBくらいまで可能。</param> /// <returns>コピーされたサンプル数。</returns> public int GetPcmOfChannel(int ch, long posSamples, ref byte[] fragment, int copySamples) { System.Diagnostics.Debug.Assert(mDecodedMetadata != null); System.Diagnostics.Debug.Assert(mPcmAllBuffer != null); System.Diagnostics.Debug.Assert(0 <= ch && ch < mDecodedMetadata.channels); int bpf = mDecodedMetadata.BytesPerFrame; int bps = mDecodedMetadata.BytesPerSample; // copySamplesを決定します。 long totalSamples = mPcmAllBuffer.LongLength / bpf; if (totalSamples < posSamples + copySamples) { copySamples = (int)(totalSamples - posSamples); } if (copySamples < 0) { copySamples = 0; } if (fragment.Length < copySamples * bps) { throw new ArgumentException("fragment is too small"); } for (int i = 0; i < copySamples; ++i) { long fromPosBytes = (posSamples + i) * bpf + ch * bps; int toPosBytes = i * bps; mPcmAllBuffer.CopyTo(fromPosBytes, ref fragment, toPosBytes, bps); } return(copySamples); }
public static LargeArray <byte> ConvertTo32bitInt( int bitsPerSample, long numSamples, PcmData.ValueRepresentationType valueType, LargeArray <byte> data) { if (bitsPerSample == 32 && valueType == PcmData.ValueRepresentationType.SInt) { // すでに所望の形式。 return(data); } var data32 = new LargeArray <byte>(numSamples * 4); switch (valueType) { case PcmData.ValueRepresentationType.SInt: switch (bitsPerSample) { case 16: for (long i = 0; i < numSamples; ++i) { short v16 = (short)( (uint)data.At(i * 2) + ((uint)data.At(i * 2 + 1) << 8)); int v32 = v16; v32 *= 65536; data32.Set(i * 4 + 0, 0); data32.Set(i * 4 + 1, 0); data32.Set(i * 4 + 2, (byte)((v32 & 0x00ff0000) >> 16)); data32.Set(i * 4 + 3, (byte)((v32 & 0xff000000) >> 24)); } return(data32); case 24: for (long i = 0; i < numSamples; ++i) { int v32 = (int)( ((uint)data.At(i * 3 + 0) << 8) + ((uint)data.At(i * 3 + 1) << 16) + ((uint)data.At(i * 3 + 2) << 24)); data32.Set(i * 4 + 0, 0); data32.Set(i * 4 + 1, (byte)((v32 & 0x0000ff00) >> 8)); data32.Set(i * 4 + 2, (byte)((v32 & 0x00ff0000) >> 16)); data32.Set(i * 4 + 3, (byte)((v32 & 0xff000000) >> 24)); } return(data32); case 32: // 所望の形式。 System.Diagnostics.Debug.Assert(false); return(null); case 64: for (long i = 0; i < numSamples; ++i) { // 16.48 fixed point int v32 = (int)( ((uint)data.At(i * 8 + 2) << 0) + ((uint)data.At(i * 8 + 3) << 8) + ((uint)data.At(i * 8 + 4) << 16) + ((uint)data.At(i * 8 + 5) << 24)); data32.Set(i * 4 + 0, (byte)((v32 & 0x000000ff) >> 0)); data32.Set(i * 4 + 1, (byte)((v32 & 0x0000ff00) >> 8)); data32.Set(i * 4 + 2, (byte)((v32 & 0x00ff0000) >> 16)); data32.Set(i * 4 + 3, (byte)((v32 & 0xff000000) >> 24)); } return(data32); default: System.Diagnostics.Debug.Assert(false); return(null); } case PcmData.ValueRepresentationType.SFloat: for (long i = 0; i < numSamples; ++i) { double v; switch (bitsPerSample) { case 32: { var b4 = new byte[4]; data.CopyTo(i * 4, ref b4, 0, 4); v = BitConverter.ToSingle(b4, 0); } break; case 64: { var b8 = new byte[8]; data.CopyTo(i * 8, ref b8, 0, 8); v = BitConverter.ToDouble(b8, 0); } break; default: System.Diagnostics.Debug.Assert(false); return(null); } int v32 = 0; if (1.0f <= v) { v32 = Int32.MaxValue; } else if (v < -1.0f) { v32 = Int32.MinValue; } else { long vMax = -((long)Int32.MinValue); long v64 = (long)(v * vMax); if (Int32.MaxValue < v64) { v64 = Int32.MaxValue; } v32 = (int)v64; } data32.Set(i * 4 + 0, (byte)((v32 & 0x000000ff) >> 0)); data32.Set(i * 4 + 1, (byte)((v32 & 0x0000ff00) >> 8)); data32.Set(i * 4 + 2, (byte)((v32 & 0x00ff0000) >> 16)); data32.Set(i * 4 + 3, (byte)((v32 & 0xff000000) >> 24)); } return(data32); default: System.Diagnostics.Debug.Assert(false); return(null); } }
/// <summary> /// サンプルフォーマットがmMetadataのmPcmDataを /// Spatial Audio用のフォーマットにリサンプルして /// mResampledPcmByChannelに入れる。 /// </summary> public int Resample() { int hr = 0; // 48000Hz 32bit floatに変換。 var fromFmt = new WWPcmFormat(WWPcmFormat.SampleFormat.SF_Int, mMetadata.numChannels, mMetadata.bitsPerSample, mMetadata.sampleRate, DwChannelMask, mMetadata.bitsPerSample); var toFmt = new WWPcmFormat(WWPcmFormat.SampleFormat.SF_Float, mMetadata.numChannels, 32, PlaySampleRate, DwChannelMask, 32); var toBufList = new List <byte[]>(); using (var resampler = new WWMFResampler()) { hr = resampler.Init(fromFmt, toFmt, RESAMPLE_QUALITY); if (hr < 0) { return(hr); } long inPos = 0; int inBytes = 1024 * 1024 * fromFmt.FrameBytes; var inBuf = new byte[inBytes]; do { // 少しずつ変換。 if (mPcmData.LongLength < inPos + inBytes) { inBytes = (int)(mPcmData.LongLength - inPos); inBuf = new byte[inBytes]; } mPcmData.CopyTo(inPos, ref inBuf, 0, inBytes); inPos += inBytes; byte[] outBuf; hr = resampler.Resample(inBuf, out outBuf); if (hr < 0) { return(hr); } if (0 < outBuf.Length) { toBufList.Add(outBuf); } outBuf = null; } while (inPos < mPcmData.LongLength); inBuf = null; { byte[] outBuf; hr = resampler.Drain(out outBuf); if (hr < 0) { return(hr); } if (0 < outBuf.Length) { toBufList.Add(outBuf); } outBuf = null; } } // 整列する。 long totalBytes = 0; foreach (var item in toBufList) { totalBytes += item.Length; } var fullPcm = WWUtil.ListUtils <byte> .GetLargeArrayFragment(toBufList, 0, totalBytes); toBufList.Clear(); toBufList = null; // fullPcmからチャンネルごとのfloatデータを取得し、 // mResampledPcmByChannelに入れる。 mResampledPcmByChannel.Clear(); int sampleBytes = toFmt.bits / 8; int nCh = toFmt.nChannels; long numFrames = totalBytes / (sampleBytes * nCh); for (int ch = 0; ch < nCh; ++ch) { var buf = new LargeArray <float>(numFrames); mResampledPcmByChannel.Add(buf); } { var buf4 = new byte[4]; var f1 = new float[1]; for (long b = 0; b < numFrames; ++b) { for (int ch = 0; ch < nCh; ++ch) { fullPcm.CopyTo(sampleBytes * (nCh * b + ch), ref buf4, 0, 4); var bufCh = mResampledPcmByChannel[ch]; f1[0] = BitConverter.ToSingle(buf4, 0); bufCh.CopyFrom(f1, 0, b, 1); } } } return(hr); }