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); }
public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcm) { WWUtil.LargeArray <double> outPcm = new WWUtil.LargeArray <double>(inPcm.LongLength); for (long i = 0; i < outPcm.LongLength; ++i) { outPcm.Set(i, inPcm.At(inPcm.LongLength - i - 1)); } return(outPcm); }
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); } }
private void SetupCoeffs() { var window = WWMath.WWWindowFunc.BlackmanWindow(UpsampledWindowLen); // ループ処理を簡単にするため最初と最後に0を置く。 mCoeffs = new WWUtil.LargeArray<double>(1 + UpsampledWindowLen + 1); long center = UpsampledWindowLen / 2; for (long i = 0; i < UpsampledWindowLen / 2 + 1; ++i) { long numerator = i; int denominator = Factor; int numeratorReminder = (int)(numerator % (denominator*2)); if (numerator == 0) { mCoeffs.Set(1 + center + i, 1.0f); } else if (numerator % denominator == 0) { // sinc(180 deg) == 0, sinc(360 deg) == 0, ... mCoeffs.Set(1 + center + i, 0.0f); } else { mCoeffs.Set(1 + center + i, Math.Sin(Math.PI * numeratorReminder / denominator) / (Math.PI * numerator / denominator) * window.At(center + i)); } mCoeffs.Set(1 + center - i, mCoeffs.At(1 + center + i)); } }
Add(WWUtil.LargeArray <double> a, WWUtil.LargeArray <double> b) { if (a.LongLength != b.LongLength) { return(null); } var result = new WWUtil.LargeArray <double>(a.LongLength); for (long i = 0; i < a.LongLength; ++i) { result.Set(i, a.At(i) + b.At(i)); } return(result); }
Mul(WWUtil.LargeArray <WWComplex> a, WWUtil.LargeArray <WWComplex> b) { if (a.LongLength != b.LongLength) { return(null); } var result = new WWUtil.LargeArray <WWComplex>(a.LongLength); for (long i = 0; i < a.LongLength; ++i) { var t = a.At(i); result.Set(i, WWComplex.Mul(t, b.At(i))); } return(result); }
private WWUtil.LargeArray <double> FFTFir(WWUtil.LargeArray <double> inPcm, double[] coef, long fftLength) { var fft = new WWMath.WWRadix2FftLargeArray(fftLength); var inTime = new WWUtil.LargeArray <WWComplex>(fftLength); for (long i = 0; i < mNumSamples; ++i) { inTime.Set(i, new WWComplex(inPcm.At(i), 0)); } var inFreq = fft.ForwardFft(inTime); inTime = null; var coefTime = new WWUtil.LargeArray <WWComplex>(fftLength); for (long i = 0; i < mCoeffs[mChannelId * 2].Length; ++i) { coefTime.Set(i, new WWComplex(coef[i], 0)); } var coefFreq = fft.ForwardFft(coefTime); coefTime = null; var mulFreq = Mul(inFreq, coefFreq); inFreq = null; coefFreq = null; var mulTime = fft.InverseFft(mulFreq); mulFreq = null; var result = new WWUtil.LargeArray <double>(inPcm.LongLength); for (int i = 0; i < inPcm.LongLength; ++i) { result.Set(i, mulTime.At(i).real); } mulTime = null; return(result); }
public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcm) { // この処理で出力するチャンネルはmChannelId // inPcmは使用しない。 double maxMagnitude = SearchMaxMagnitude(); double gain = Magnitude / maxMagnitude; var s = mPcmAllChannels[mChannelId]; var result = new WWUtil.LargeArray <double>(mNumSamples); for (long i = 0; i < mNumSamples; ++i) { result.Set(i, s.At(i) * gain); } return(result); }
public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA) { var y = new WWUtil.LargeArray <double>(inPcmLA.LongLength); for (long pos = 0; pos < inPcmLA.LongLength; ++pos) { double x = inPcmLA.At(pos); x = mScale * x; foreach (var f in mF) { x = f.Filter(x); } y.Set(pos, x); } return(y); }
/// <summary> /// サンプル値セット。フォーマットがSintの場合のみ使用可能。 /// サンプル値は符号付32bit int値で、0x8000000 ~ 0x7fffffffの値。 /// </summary> public void SetSampleValueInInt32(int ch, long pos, int val) { Debug.Assert(SampleValueRepresentationType == ValueRepresentationType.SInt); Debug.Assert(0 <= ch && ch < NumChannels); if (pos < 0 || NumFrames <= pos) { return; } long offset = pos * BitsPerFrame / 8 + ch * BitsPerSample / 8; switch (BitsPerSample) { case 16: mSampleLargeArray.Set(offset + 0, (byte)(0xff & (val >> 16))); mSampleLargeArray.Set(offset + 1, (byte)(0xff & (val >> 24))); return; case 24: mSampleLargeArray.Set(offset + 0, (byte)(0xff & (val >> 8))); mSampleLargeArray.Set(offset + 1, (byte)(0xff & (val >> 16))); mSampleLargeArray.Set(offset + 2, (byte)(0xff & (val >> 24))); return; case 32: switch (ValidBitsPerSample) { case 24: mSampleLargeArray.Set(offset + 0, 0); mSampleLargeArray.Set(offset + 1, (byte)(0xff & (val >> 8))); mSampleLargeArray.Set(offset + 2, (byte)(0xff & (val >> 16))); mSampleLargeArray.Set(offset + 3, (byte)(0xff & (val >> 24))); return; case 32: mSampleLargeArray.Set(offset + 0, (byte)(0xff & (val))); mSampleLargeArray.Set(offset + 1, (byte)(0xff & (val >> 8))); mSampleLargeArray.Set(offset + 2, (byte)(0xff & (val >> 16))); mSampleLargeArray.Set(offset + 3, (byte)(0xff & (val >> 24))); return; default: System.Diagnostics.Debug.Assert(false); return; } default: System.Diagnostics.Debug.Assert(false); return; } }
public WWUtil.LargeArray <double> GetDoubleArray(int ch) { var r = new WWUtil.LargeArray <double>(NumFrames); if (SampleValueRepresentationType == ValueRepresentationType.SFloat) { switch (BitsPerSample) { case 32: for (long i = 0; i < NumFrames; ++i) { float v = GetSampleValueInFloat(ch, i); r.Set(i, v); } break; case 64: for (long i = 0; i < NumFrames; ++i) { double v = GetSampleValueInDouble(ch, i); r.Set(i, v); } break; default: System.Diagnostics.Debug.Assert(false); break; } } else { var f = GetSampleLargeArray(); long readPos = 0; long writePos = 0; switch (BitsPerSample) { case 16: for (int i = 0; i < NumFrames; ++i) { for (int c = 0; c < NumChannels; ++c) { if (c == ch) { short v = (short)(f.At(readPos) + f.At(readPos + 1) << 8); r.Set(writePos++, v / 32768.0); } readPos += 2; } } break; case 24: for (int i = 0; i < NumFrames; ++i) { for (int c = 0; c < NumChannels; ++c) { if (c == ch) { int v = (int)((f.At(readPos) << 8) + (f.At(readPos + 1) << 16) + (f.At(readPos + 2) << 24)); r.Set(writePos++, v / 2147483648.0); } readPos += 3; } } break; case 32: for (int i = 0; i < NumFrames; ++i) { for (int c = 0; c < NumChannels; ++c) { if (c == ch) { int v = (int)((f.At(readPos) << 0) + (f.At(readPos + 1) << 8) + (f.At(readPos + 2) << 16) + (f.At(readPos + 3) << 24)); r.Set(writePos++, v / 2147483648.0); } readPos += 4; } } break; case 64: // 16.48 fixed point numberを想定。 for (int i = 0; i < NumFrames; ++i) { for (int c = 0; c < NumChannels; ++c) { if (c == ch) { long v = (long)( (((long)f.At(readPos)) << 0) + ((long)(f.At(readPos + 1)) << 8) + ((long)(f.At(readPos + 2)) << 16) + ((long)(f.At(readPos + 3)) << 24) + ((long)(f.At(readPos + 4)) << 32) + ((long)(f.At(readPos + 5)) << 40) + ((long)(f.At(readPos + 6)) << 48) + ((long)(f.At(readPos + 7)) << 56) ); r.Set(writePos++, v / 65536.0 / 65536.0 / 65536.0); } readPos += 8; } } break; default: System.Diagnostics.Debug.Assert(false); break; } } return(r); }
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 ReadWavFile(string path, out AudioData ad) { ad = new AudioData(); using (var br = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))) { var reader = new WavRWLib2.WavReader(); if (!reader.ReadHeaderAndSamples(br, 0, -1)) { MessageBox.Show( string.Format("Error: Failed to read WAV file: {0}", path)); return(-1); } ad.meta = new WWFlacRWCS.Metadata(); ad.meta.albumStr = reader.AlbumName; ad.meta.artistStr = reader.ArtistName; ad.meta.titleStr = reader.Title; ad.meta.pictureBytes = reader.PictureBytes; ad.picture = reader.PictureData; ad.meta.totalSamples = reader.NumFrames; ad.meta.channels = reader.NumChannels; ad.meta.sampleRate = reader.SampleRate; var interleaved = reader.GetSampleLargeArray(); int bytesPerSample = reader.BitsPerSample / 8; ad.pcm = new List <AudioDataPerChannel>(); for (int ch = 0; ch < reader.NumChannels; ++ch) { var pcmOneChannel = new WWUtil.LargeArray <byte>(reader.NumFrames * bytesPerSample); for (long i = 0; i < reader.NumFrames; ++i) { for (int b = 0; b < reader.BitsPerSample / 8; ++b) { pcmOneChannel.Set(bytesPerSample * i + b, interleaved.At(bytesPerSample * (reader.NumChannels * i + ch) + b)); } } #if true var adp = new AudioDataPerChannel(); adp.mData = pcmOneChannel; adp.mOffsBytes = 0; adp.mBitsPerSample = reader.BitsPerSample; adp.mValueRepresentationType = reader.SampleValueRepresentationType; #else var pcm32 = PcmDataLib.PcmDataUtil.ConvertTo32bitInt(reader.BitsPerSample, reader.NumFrames, reader.SampleValueRepresentationType, pcmOneChannel); var adp = new AudioDataPerChannel(); adp.mData = pcm32; adp.mOffsBytes = 0; adp.mBitsPerSample = 32; adp.mValueRepresentationType = PcmDataLib.PcmData.ValueRepresentationType.SInt; #endif adp.mTotalSamples = ad.meta.totalSamples; ad.pcm.Add(adp); } ad.meta.bitsPerSample = reader.BitsPerSample; ad.preferredSaveFormat = WWAFUtil.FileFormatType.FLAC; if (24 < ad.meta.bitsPerSample) { ad.preferredSaveFormat = WWAFUtil.FileFormatType.WAVE; } return(0); } }
private int SetupResultPcm(AudioData from, List <FilterBase> filters, out AudioData to, WWAFUtil.FileFormatType toFileFormat, WWAFUtil.AFSampleFormat toSampleFormat) { to = new AudioData(); to.preferredSaveFormat = toFileFormat; var fmt = FilterSetup(from, 0, filters); if (null == fmt) { return(-1); } to.meta = new WWFlacRWCS.Metadata(from.meta); to.meta.sampleRate = fmt.SampleRate; to.meta.totalSamples = fmt.NumSamples; to.meta.channels = fmt.NumChannels; to.writeValueRepresentation = PcmDataLib.PcmData.ValueRepresentationType.SInt; switch (toSampleFormat) { case WWAFUtil.AFSampleFormat.Auto: // auto selection. switch (toFileFormat) { case WWAFUtil.FileFormatType.FLAC: to.meta.bitsPerSample = 24; break; case WWAFUtil.FileFormatType.WAVE: to.meta.bitsPerSample = 32; break; case WWAFUtil.FileFormatType.DSF: to.meta.bitsPerSample = 1; break; } break; case WWAFUtil.AFSampleFormat.PcmInt16: to.meta.bitsPerSample = 16; break; case WWAFUtil.AFSampleFormat.PcmInt24: to.meta.bitsPerSample = 24; break; case WWAFUtil.AFSampleFormat.PcmInt32: to.meta.bitsPerSample = 32; break; case WWAFUtil.AFSampleFormat.PcmFloat32: to.meta.bitsPerSample = 32; to.writeValueRepresentation = PcmDataLib.PcmData.ValueRepresentationType.SFloat; break; case WWAFUtil.AFSampleFormat.PcmInt64: to.meta.bitsPerSample = 64; break; case WWAFUtil.AFSampleFormat.PcmFloat64: to.meta.bitsPerSample = 64; to.writeValueRepresentation = PcmDataLib.PcmData.ValueRepresentationType.SFloat; break; } if (from.picture != null) { to.picture = new byte[from.picture.Length]; System.Array.Copy(from.picture, to.picture, to.picture.Length); } // allocate "to" pcm data to.pcm = new List <AudioDataPerChannel>(); for (int ch = 0; ch < to.meta.channels; ++ch) { WWUtil.LargeArray <byte> data; // set silent sample values to output buffer switch (toFileFormat) { case WWAFUtil.FileFormatType.DSF: data = new WWUtil.LargeArray <byte>((to.meta.totalSamples + 7) / 8); for (long i = 0; i < data.LongLength; ++i) { data.Set(i, 0x69); } break; case WWAFUtil.FileFormatType.FLAC: if (655350 < to.meta.sampleRate) { return((int)WWFlacRWCS.FlacErrorCode.InvalidSampleRate); } data = new WWUtil.LargeArray <byte>(to.meta.totalSamples * (to.meta.bitsPerSample / 8)); break; case WWAFUtil.FileFormatType.WAVE: data = new WWUtil.LargeArray <byte>(to.meta.totalSamples * (to.meta.bitsPerSample / 8)); break; default: System.Diagnostics.Debug.Assert(false); data = null; break; } var adp = new AudioDataPerChannel(); adp.mDataFormat = AudioDataPerChannel.DataFormat.Pcm; adp.mData = data; adp.mBitsPerSample = to.meta.bitsPerSample; adp.mValueRepresentationType = to.writeValueRepresentation; adp.mTotalSamples = to.meta.totalSamples; to.pcm.Add(adp); } return(0); }
/// <param name="pcm">コピー元データ。先頭から全要素コピーする。</param> /// <param name="writePos">コピー先(この配列)先頭要素数。</param> public void SetPcmInDouble(double[] pcm, long writePos) { if (mBitsPerSample == 1 && 0 != (writePos & 7)) { throw new ArgumentException("writeOffs must be multiple of 8"); } int copyCount = pcm.Length; if (mTotalSamples < writePos + copyCount) { copyCount = (int)(mTotalSamples - writePos); } long writePosBytes; switch (mBitsPerSample) { case 1: { long readPos = 0; // set 1bit data (from LSB to MSB) into 8bit buffer writePosBytes = writePos / 8; for (long i = 0; i < copyCount / 8; ++i) { byte sampleValue = 0; for (int subPos = 0; subPos < 8; ++subPos) { byte bit = (0 <= pcm[readPos]) ? (byte)(1 << subPos) : (byte)0; sampleValue |= bit; ++readPos; } mData.Set(writePosBytes, sampleValue); ++writePosBytes; } } break; case 16: writePosBytes = writePos * 2; for (long i = 0; i < copyCount; ++i) { short vS = 0; double vD = pcm[i]; if (vD < -1.0f) { vS = -32768; mOverflow = true; if (mMaxMagnitude < Math.Abs(vD)) { mMaxMagnitude = Math.Abs(vD); } } else if (1.0f <= vD) { vS = 32767; mOverflow = true; if (mMaxMagnitude < Math.Abs(vD)) { mMaxMagnitude = Math.Abs(vD); } } else { vS = (short)(32768.0 * vD); } mData.Set(writePosBytes + 0, (byte)((vS) & 0xff)); mData.Set(writePosBytes + 1, (byte)((vS >> 8) & 0xff)); writePosBytes += 2; } break; case 24: writePosBytes = writePos * 3; for (long i = 0; i < copyCount; ++i) { int vI = 0; double vD = pcm[i]; if (vD < -1.0f) { vI = Int32.MinValue; mOverflow = true; if (mMaxMagnitude < Math.Abs(vD)) { mMaxMagnitude = Math.Abs(vD); } } else if (1.0f <= vD) { vI = 0x7fffff00; mOverflow = true; if (mMaxMagnitude < Math.Abs(vD)) { mMaxMagnitude = Math.Abs(vD); } } else { vI = (int)(2147483648.0 * vD); } mData.Set(writePosBytes + 0, (byte)((vI >> 8) & 0xff)); mData.Set(writePosBytes + 1, (byte)((vI >> 16) & 0xff)); mData.Set(writePosBytes + 2, (byte)((vI >> 24) & 0xff)); writePosBytes += 3; } break; case 32: switch (mValueRepresentationType) { case PcmData.ValueRepresentationType.SInt: // 32bit int. writePosBytes = writePos * 4; for (long i = 0; i < copyCount; ++i) { int vI = 0; double vD = pcm[i]; if (vD < -1.0f) { vI = Int32.MinValue; mOverflow = true; if (mMaxMagnitude < Math.Abs(vD)) { mMaxMagnitude = Math.Abs(vD); } } else if (1.0f <= vD) { vI = 0x7fffffff; mOverflow = true; if (mMaxMagnitude < Math.Abs(vD)) { mMaxMagnitude = Math.Abs(vD); } } else { vI = (int)(2147483648.0 * vD); } mData.Set(writePosBytes + 0, (byte)((vI >> 0) & 0xff)); mData.Set(writePosBytes + 1, (byte)((vI >> 8) & 0xff)); mData.Set(writePosBytes + 2, (byte)((vI >> 16) & 0xff)); mData.Set(writePosBytes + 3, (byte)((vI >> 24) & 0xff)); writePosBytes += 4; } break; case PcmData.ValueRepresentationType.SFloat: // 32bit Float. writePosBytes = writePos * 4; for (long i = 0; i < copyCount; ++i) { double vD = pcm[i]; float vF = (float)vD; var b4 = BitConverter.GetBytes(vF); for (int j = 0; j < 4; ++j) { mData.Set(writePosBytes + j, b4[j]); } writePosBytes += 4; } break; } break; case 64: switch (mValueRepresentationType) { case PcmData.ValueRepresentationType.SInt: //64bit int. writePosBytes = writePos * 8; for (long i = 0; i < copyCount; ++i) { long vI = 0; double vD = pcm[i]; // 16:48 fixed point number if (vD < -32768.0) { vI = long.MinValue; mOverflow = true; if (mMaxMagnitude < Math.Abs(vD)) { mMaxMagnitude = Math.Abs(vD); } } else if (32768.0 <= vD) { vI = long.MaxValue; mOverflow = true; if (mMaxMagnitude < Math.Abs(vD)) { mMaxMagnitude = Math.Abs(vD); } } else { vI = (long)(65536.0 * 65536.0 * 65536.0 * vD); } for (int j = 0; j < 8; ++j) { mData.Set(writePosBytes + j, (byte)((vI >> (j * 8)) & 0xff)); } writePosBytes += 8; } break; case PcmData.ValueRepresentationType.SFloat: // 64bit float. writePosBytes = writePos * 8; for (long i = 0; i < copyCount; ++i) { double vD = pcm[i]; var b8 = BitConverter.GetBytes(vD); for (int j = 0; j < 8; ++j) { mData.Set(writePosBytes + j, b8[j]); } writePosBytes += 8; } break; } break; default: System.Diagnostics.Debug.Assert(false); break; } }