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; } })); }
/// <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[] 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; } })); }
public SampleDataAsset(string name, WaveFile wave) { if (name == null) { throw new ArgumentNullException("An asset must be given a valid name."); } assetName = name; SamplerChunk smpl = wave.FindChunk <SamplerChunk>(); if (smpl != null) { sampleRate = (int)(44100.0 * (1.0 / (smpl.SamplePeriod / 22675.0))); rootKey = (short)smpl.UnityNote; tune = (short)(smpl.PitchFraction * 100); if (smpl.Loops.Length > 0) { //--WARNING ASSUMES: smpl.Loops[0].Type == SamplerChunk.SampleLoop.LoopType.Forward loopStart = smpl.Loops[0].Start; loopEnd = smpl.Loops[0].End + smpl.Loops[0].Fraction + 1; } } else { sampleRate = wave.Format.SampleRate; } byte[] data = wave.Data.RawSampleData; if (wave.Format.ChannelCount != audioChannels) //reformat to supported channels { data = WaveHelper.GetChannelPcmData(data, wave.Format.BitsPerSample, wave.Format.ChannelCount, audioChannels); } sampleData = PcmData.Create(wave.Format.BitsPerSample, data, true); start = 0; end = sampleData.Length; }
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; } })); }
/// <summary> /// 量子化ビット数を、もし必要なら変更する。 /// </summary> /// <param name="pd">入力PcmData</param> /// <returns>変更後PcmData</returns> public PcmData BitsPerSampleConvAsNeeded(PcmData pd, WasapiCS.SampleFormatType fmt, WasapiPcmUtil.PcmFormatConverter.BitsPerSampleConvArgs args) { switch (fmt) { case WasapiCS.SampleFormatType.Sfloat: // System.Console.WriteLine("Converting to Sfloat32bit..."); pd = mConv.Convert(pd, WasapiCS.SampleFormatType.Sfloat, args); break; case WasapiCS.SampleFormatType.Sint16: // System.Console.WriteLine("Converting to SInt16bit..."); pd = mConv.Convert(pd, WasapiCS.SampleFormatType.Sint16, args); break; case WasapiCS.SampleFormatType.Sint24: // System.Console.WriteLine("Converting to SInt24..."); pd = mConv.Convert(pd, WasapiCS.SampleFormatType.Sint24, args); break; case WasapiCS.SampleFormatType.Sint32V24: // System.Console.WriteLine("Converting to SInt32V24..."); pd = mConv.Convert(pd, WasapiCS.SampleFormatType.Sint32V24, args); break; case WasapiCS.SampleFormatType.Sint32: // System.Console.WriteLine("Converting to SInt32bit..."); pd = mConv.Convert(pd, WasapiCS.SampleFormatType.Sint32, args); break; default: System.Diagnostics.Debug.Assert(false); break; } return(pd); }
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; } })); }
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); }
/// <summary> /// WAVファイルのヘッダ部分を読み込む。 /// </summary> /// <returns>読めたらtrue</returns> private bool ReadWavFileHeader(string path) { bool result = false; var pd = new 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 (wavR.SampleDataType == WavReader.DataType.DoP) { pd.SampleDataType = PcmData.DataType.DoP; } 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; } if (wavR.ComposerName != null) { pd.ComposerName = wavR.ComposerName; } } 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); }
/// <summary> /// 1曲再生のプレイリストをap.PcmDataListForPlayに作成。 /// </summary> public void CreateOneTrackPlayList(int wavDataId) { var pcmData = new PcmData(); pcmData.CopyFrom(m_pcmDataListForDisp.FindById(wavDataId)); pcmData.GroupId = 0; m_pcmDataListForPlay = new PcmDataList(); m_pcmDataListForPlay.Add(pcmData); }
/// <summary> /// 全曲が表示順に並んでいる再生リストap.PcmDataListForPlayを作成。 /// </summary> public void CreateAllTracksPlayList() { m_pcmDataListForPlay = new PcmDataList(); for (int i = 0; i < m_pcmDataListForDisp.Count(); ++i) { var pcmData = new PcmData(); pcmData.CopyFrom(m_pcmDataListForDisp.At(i)); m_pcmDataListForPlay.Add(pcmData); } }
public override void Perform(AudioData audio, PreviewImageQuery query) { int desiredWidth = query.DesiredWidth; int desiredHeight = query.DesiredHeight; int oggHash = audio.OggVorbisData.GetCombinedHashCode(); int oggLen = audio.OggVorbisData.Length; PcmData pcm = OggVorbis.LoadChunkFromMemory(audio.OggVorbisData, 500000); short[] sdata = pcm.data; short maxVal = 1; for (int i = 0; i < pcm.dataLength; i++) { maxVal = Math.Max(maxVal, Math.Abs(pcm.data[i])); } Bitmap result = new Bitmap(desiredWidth, desiredHeight); int channelLength = pcm.dataLength / pcm.channelCount; int yMid = result.Height / 2; int stepWidth = (channelLength / (2 * result.Width)) - 1; const int samples = 10; using (Graphics g = Graphics.FromImage(result)) { Color baseColor = ExtMethodsColor.ColorFromHSV( (float)(oggHash % 90) * (float)(oggLen % 4) / 360.0f, 0.5f, 1f); Pen linePen = new Pen(Color.FromArgb(MathF.RoundToInt(255.0f / MathF.Pow((float)samples, 0.65f)), baseColor)); g.Clear(Color.Transparent); for (int x = 0; x < result.Width; x++) { float invMaxVal = 2.0f / ((float)maxVal + (float)short.MaxValue); float timePercentage = (float)x / (float)result.Width; int i = MathF.RoundToInt(timePercentage * channelLength); float left; float right; short channel1; short channel2; for (int s = 0; s <= samples; s++) { int offset = stepWidth * s / samples; channel1 = sdata[(i + offset) * pcm.channelCount + 0]; channel2 = sdata[(i + offset) * pcm.channelCount + 1]; left = (float)Math.Abs(channel1) * invMaxVal; right = (float)Math.Abs(channel2) * invMaxVal; g.DrawLine(linePen, x, yMid, x, yMid + MathF.RoundToInt(left * yMid)); g.DrawLine(linePen, x, yMid, x, yMid - MathF.RoundToInt(right * yMid)); } } } query.Result = result; }
public SampleDataAsset(SampleHeader sample, SoundFontSampleData sampleData) { this.assetName = sample.Name; this.sampleRate = sample.SampleRate; this.rootKey = sample.RootKey; this.tune = sample.Tune; this.start = sample.Start; this.end = sample.End; this.loopStart = sample.StartLoop; this.loopEnd = sample.EndLoop; this.sampleData = PcmData.Create(sampleData.BitsPerSample, sampleData.SampleData, true); }
/// <summary> /// 読み込み処理を終了する。 /// </summary> /// <returns>Error code</returns> public int StreamEnd() { int rv = 0; mMD5SumInMetadata = null; mMD5SumOfPcm = null; switch (m_format) { case Format.FLAC: rv = mFlacR.ReadEnd(); 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; case Format.MP3: mMp3Reader.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); }
private bool WriteWavFile(PcmData pcmData, string path) { using (BinaryWriter bw = new BinaryWriter( File.Open(path, FileMode.Create, FileAccess.Write, FileShare.Write))) { var wavW = new WavWriter(); wavW.Set(pcmData.NumChannels, pcmData.BitsPerSample, pcmData.ValidBitsPerSample, pcmData.SampleRate, pcmData.SampleValueRepresentationType, pcmData.NumFrames, pcmData.GetSampleArray()); wavW.Write(bw); } return(true); }
private void buttonPlayA_Click(object sender, RoutedEventArgs e) { int hr; PcmData pcmData = ReadWavFile(textBoxPathA.Text); if (null == pcmData) { MessageBox.Show( string.Format("WAVファイル A 読み込み失敗: {0}", textBoxPathA.Text)); return; } /* * hr = wasapi.ChooseDevice(comboBoxDeviceA.SelectedIndex); * if (hr < 0) { * MessageBox.Show(string.Format("Wasapi.ChooseDevice()失敗 {0:X8}", hr)); * UnchooseRecreateDeviceList(); * return; * } */ hr = WasapiSetup( comboBoxDeviceA.SelectedIndex, radioButtonExclusiveA.IsChecked == true, radioButtonEventDrivenA.IsChecked == true, pcmData.SampleRate, pcmData.BitsPerSample, pcmData.ValidBitsPerSample, pcmData.SampleValueRepresentationType, Int32.Parse(textBoxLatencyA.Text)); if (hr < 0) { MessageBox.Show(string.Format("Wasapi.Setup失敗 {0:X8}", hr)); UnchooseRecreateDeviceList(); return; } var pcmUtil = new PcmUtil(pcmData.NumChannels); pcmData = pcmUtil.BitsPerSampleConvAsNeeded(pcmData, m_sampleFormat.GetSampleFormatType(), null); wasapi.ClearPlayList(); wasapi.AddPlayPcmDataStart(); wasapi.AddPlayPcmData(0, pcmData.GetSampleArray()); wasapi.AddPlayPcmDataEnd(); hr = wasapi.StartPlayback(0); m_playWorker.RunWorkerAsync(); m_status = Status.Play; UpdateAbxTabUIStatus(); }
private PcmData FlacScanDopMarker(PcmData pcmData, FlacDecodeIF fdif) { // 1個PCMデータを読み出す。 int ercd = 0; var buff = fdif.ReadStreamReadOne(PcmDataLib.PcmData.DOP_SCAN_FRAMES, out ercd); bool bDoP = pcmData.ScanDopMarker(buff); if (bDoP) { pcmData.SampleDataType = PcmData.DataType.DoP; } return(pcmData); }
public SampleDataAsset(SampleHeader sample, SoundFontSampleData sampleData) { Channels = 1; Name = sample.Name; SampleRate = sample.SampleRate; RootKey = sample.RootKey; Tune = sample.Tune; Start = sample.Start; End = sample.End; LoopStart = sample.StartLoop; LoopEnd = sample.EndLoop; SampleData = PcmData.Create(sampleData.BitsPerSample, sampleData.SampleData, true); }
private byte[] ConvI16toI24(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 16-bit: copy PCM to[toPos++] = from[fromPos++]; to[toPos++] = from[fromPos++]; } })); }
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; } })); }
/// <summary> /// シャッフルした再生リストap.PcmDataListForPlayを作成する /// </summary> public void CreateShuffledPlayList() { // 適当にシャッフルされた番号が入っている配列pcmDataIdxArrayを作成。 var pcmDataIdxArray = new int[PcmDataListForDisp.Count()]; for (int i = 0; i < pcmDataIdxArray.Length; ++i) { pcmDataIdxArray[i] = i; } var gen = new RNGCryptoServiceProvider(); int N = pcmDataIdxArray.Length; for (int i = 0; i < N * 100; ++i) { var a = GetRandomNumber(gen, N); var b = GetRandomNumber(gen, N); if (a == b) { // 入れ替え元と入れ替え先が同じ。あんまり意味ないのでスキップする。 continue; } // a番目とb番目を入れ替える var tmp = pcmDataIdxArray[a]; pcmDataIdxArray[a] = pcmDataIdxArray[b]; pcmDataIdxArray[b] = tmp; } // ap.PcmDataListForPlayを作成。 m_pcmDataListForPlay = new PcmDataList(); for (int i = 0; i < pcmDataIdxArray.Length; ++i) { var idx = pcmDataIdxArray[i]; // 再生順番号Ordinalを付け直す // GroupIdをバラバラの番号にする(1曲ずつ読み込む) var pcmData = new PcmData(); pcmData.CopyFrom(m_pcmDataListForDisp.At(idx)); pcmData.Ordinal = i; pcmData.GroupId = i; m_pcmDataListForPlay.Add(pcmData); } }
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; } })); }
private PcmData ReadWavFile(string path) { PcmData pcmData = new PcmData(); using (BinaryReader br = new BinaryReader( File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))) { var wavR = new WavReader(); bool readSuccess = wavR.ReadHeaderAndSamples(br, 0, -1); if (!readSuccess) { return(null); } pcmData.SetFormat(wavR.NumChannels, wavR.BitsPerSample, wavR.BitsPerSample, wavR.SampleRate, wavR.SampleValueRepresentationType, wavR.NumFrames); pcmData.SetSampleArray(wavR.GetSampleArray()); } return(pcmData); }
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; } })); }
public SampleDataAsset(int size, BinaryReader reader) { assetName = IOHelper.Read8BitString(reader, 20); sampleRate = reader.ReadInt32(); rootKey = reader.ReadInt16(); tune = reader.ReadInt16(); loopStart = reader.ReadDouble(); loopEnd = reader.ReadDouble(); byte bits = reader.ReadByte(); byte chans = reader.ReadByte(); byte[] data = reader.ReadBytes(size - 46); if (chans != audioChannels) //reformat to supported channels { data = WaveHelper.GetChannelPcmData(data, bits, chans, audioChannels); } sampleData = PcmData.Create(bits, data, true); start = 0; end = sampleData.Length; }
public SampleDataAsset(SampleHeader sample, SoundFontSampleData sampleData) { Channels = 1; Name = sample.Name; SampleRate = sample.SampleRate; RootKey = sample.RootKey; Tune = sample.Tune; Start = sample.Start; End = sample.End; LoopStart = sample.StartLoop; LoopEnd = sample.EndLoop; if ((sample.SoundFontSampleLink & SFSampleLink.OggVobis) != 0) { throw new Exception("Ogg Vobis encoded soundfonts not supported"); } else { SampleData = PcmData.Create(sampleData.BitsPerSample, sampleData.SampleData, true); } }
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; }
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[] 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; } })); }
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); }
// --- functions --- /// <summary>Reads wave data from a RIFF/WAVE/PCM file.</summary> /// <param name="fileName">The file name of the RIFF/WAVE/PCM file.</param> /// <returns>The wave data.</returns> /// <remarks>Both RIFF and RIFX container formats are supported by this function.</remarks> internal static WaveData LoadFromFile(string fileName) { string fileTitle = Path.GetFileName(fileName); byte[] fileBytes = File.ReadAllBytes(fileName); using (MemoryStream stream = new MemoryStream(fileBytes)) { using (BinaryReader reader = new BinaryReader(stream)) { // RIFF/RIFX chunk Endianness endianness; uint headerCkID = reader.ReadUInt32(); /* Chunk ID is character-based */ if (headerCkID == 0x46464952) { endianness = Endianness.Little; } else if (headerCkID == 0x58464952) { endianness = Endianness.Big; } else { throw new InvalidDataException("Invalid chunk ID in " + fileTitle); } uint headerCkSize = ReadUInt32(reader, endianness); uint formType = ReadUInt32(reader, endianness); if (formType != 0x45564157) { throw new InvalidDataException("Unsupported format in " + fileTitle); } // data chunks WaveFormat format = new WaveFormat(); FormatData data = null; byte[] dataBytes = null; while (stream.Position + 8 <= stream.Length) { uint ckID = reader.ReadUInt32(); /* Chunk ID is character-based */ uint ckSize = ReadUInt32(reader, endianness); if (ckID == 0x20746d66) { // "fmt " chunk if (ckSize < 14) { throw new InvalidDataException("Unsupported fmt chunk size in " + fileTitle); } ushort wFormatTag = ReadUInt16(reader, endianness); ushort wChannels = ReadUInt16(reader, endianness); uint dwSamplesPerSec = ReadUInt32(reader, endianness); if (dwSamplesPerSec >= 0x80000000) { throw new InvalidDataException("Unsupported dwSamplesPerSec in " + fileTitle); } uint dwAvgBytesPerSec = ReadUInt32(reader, endianness); ushort wBlockAlign = ReadUInt16(reader, endianness); if (wFormatTag == 1) { // PCM if (ckSize < 16) { throw new InvalidDataException("Unsupported fmt chunk size in " + fileTitle); } ushort wBitsPerSample = ReadUInt16(reader, endianness); stream.Position += ckSize - 16; if (wBitsPerSample < 1) { throw new InvalidDataException("Unsupported wBitsPerSample in " + fileTitle); } if (wBlockAlign != ((wBitsPerSample + 7) / 8) * wChannels) { throw new InvalidDataException("Unexpected wBlockAlign in " + fileTitle); } format.SampleRate = (int)dwSamplesPerSec; format.BitsPerSample = (int)wBitsPerSample; format.Channels = (int)wChannels; PcmData pcmData = new PcmData(); pcmData.BlockSize = (int)wBlockAlign; data = pcmData; } else if (wFormatTag == 2) { // Microsoft ADPCM if (ckSize < 22) { throw new InvalidDataException("Unsupported fmt chunk size in " + fileTitle); } ushort wBitsPerSample = ReadUInt16(reader, endianness); if (wBitsPerSample != 4) { throw new InvalidDataException("Unsupported wBitsPerSample in " + fileTitle); } ushort cbSize = ReadUInt16(reader, endianness); MicrosoftAdPcmData adpcmData = new MicrosoftAdPcmData(); adpcmData.SamplesPerBlock = ReadUInt16(reader, endianness); if (adpcmData.SamplesPerBlock == 0 | adpcmData.SamplesPerBlock > 2 * ((int)wBlockAlign - 6)) { throw new InvalidDataException("Unexpected nSamplesPerBlock in " + fileTitle); } ushort wNumCoef = ReadUInt16(reader, endianness); if (ckSize < 22 + 4 * wNumCoef) { throw new InvalidDataException("Unsupported fmt chunk size in " + fileTitle); } adpcmData.Coefficients = new short[wNumCoef][]; for (int i = 0; i < wNumCoef; i++) { unchecked { adpcmData.Coefficients[i] = new short[] { (short)ReadUInt16(reader, endianness), (short)ReadUInt16(reader, endianness) }; } } stream.Position += ckSize - (22 + 4 * wNumCoef); format.SampleRate = (int)dwSamplesPerSec; format.BitsPerSample = 16; format.Channels = (int)wChannels; adpcmData.BlockSize = wBlockAlign; data = adpcmData; } else { // unsupported format throw new InvalidDataException("Unsupported wFormatTag in " + fileTitle); } } else if (ckID == 0x61746164) { // "data" chunk if (ckSize >= 0x80000000) { throw new InvalidDataException("Unsupported data chunk size in " + fileTitle); } if (data is PcmData) { // PCM int bytesPerSample = (format.BitsPerSample + 7) / 8; int samples = (int)ckSize / (format.Channels * bytesPerSample); int dataSize = samples * format.Channels * bytesPerSample; dataBytes = reader.ReadBytes(dataSize); stream.Position += ckSize - dataSize; } else if (data is MicrosoftAdPcmData) { // Microsoft ADPCM MicrosoftAdPcmData adpcmData = (MicrosoftAdPcmData)data; int blocks = (int)ckSize / adpcmData.BlockSize; dataBytes = new byte[2 * blocks * format.Channels * adpcmData.SamplesPerBlock]; int position = 0; for (int i = 0; i < blocks; i++) { unchecked { MicrosoftAdPcmData.ChannelData[] channelData = new MicrosoftAdPcmData.ChannelData[format.Channels]; for (int j = 0; j < format.Channels; j++) { channelData[j].bPredictor = (int)reader.ReadByte(); if (channelData[j].bPredictor >= adpcmData.Coefficients.Length) { throw new InvalidDataException("Invalid bPredictor in " + fileTitle); } channelData[j].iCoef1 = (int)adpcmData.Coefficients[channelData[j].bPredictor][0]; channelData[j].iCoef2 = (int)adpcmData.Coefficients[channelData[j].bPredictor][1]; } for (int j = 0; j < format.Channels; j++) { channelData[j].iDelta = (short)ReadUInt16(reader, endianness); } for (int j = 0; j < format.Channels; j++) { channelData[j].iSamp1 = (short)ReadUInt16(reader, endianness); } for (int j = 0; j < format.Channels; j++) { channelData[j].iSamp2 = (short)ReadUInt16(reader, endianness); } for (int j = 0; j < format.Channels; j++) { dataBytes[position] = (byte)(ushort)channelData[j].iSamp2; dataBytes[position + 1] = (byte)((ushort)channelData[j].iSamp2 >> 8); position += 2; } for (int j = 0; j < format.Channels; j++) { dataBytes[position] = (byte)(ushort)channelData[j].iSamp1; dataBytes[position + 1] = (byte)((ushort)channelData[j].iSamp1 >> 8); position += 2; } uint nibbleByte = 0; bool nibbleFirst = true; for (int j = 0; j < adpcmData.SamplesPerBlock - 2; j++) { for (int k = 0; k < format.Channels; k++) { int lPredSample = (int)channelData[k].iSamp1 * channelData[k].iCoef1 + (int)channelData[k].iSamp2 * channelData[k].iCoef2 >> 8; int iErrorDeltaUnsigned; if (nibbleFirst) { nibbleByte = (uint)reader.ReadByte(); iErrorDeltaUnsigned = (int)(nibbleByte >> 4); nibbleFirst = false; } else { iErrorDeltaUnsigned = (int)(nibbleByte & 15); nibbleFirst = true; } int iErrorDeltaSigned = iErrorDeltaUnsigned >= 8 ? iErrorDeltaUnsigned - 16 : iErrorDeltaUnsigned; int lNewSampInt = lPredSample + (int)channelData[k].iDelta * iErrorDeltaSigned; short lNewSamp = lNewSampInt <= -32768 ? (short)-32768 : lNewSampInt >= 32767 ? (short)32767 : (short)lNewSampInt; channelData[k].iDelta = (short)( (int)channelData[k].iDelta * (int)MicrosoftAdPcmData.AdaptionTable[iErrorDeltaUnsigned] >> 8 ); if (channelData[k].iDelta < 16) { channelData[k].iDelta = 16; } channelData[k].iSamp2 = channelData[k].iSamp1; channelData[k].iSamp1 = lNewSamp; dataBytes[position] = (byte)(ushort)lNewSamp; dataBytes[position + 1] = (byte)((ushort)lNewSamp >> 8); position += 2; } } } stream.Position += adpcmData.BlockSize - (format.Channels * (adpcmData.SamplesPerBlock - 2) + 1 >> 1) - 7 * format.Channels; } stream.Position += (int)ckSize - blocks * adpcmData.BlockSize; } else { // invalid throw new InvalidDataException("No fmt chunk before the data chunk in " + fileTitle); } } else { // unsupported chunk stream.Position += (long)ckSize; } // pad byte if ((ckSize & 1) == 1) { stream.Position++; } } // finalize if (dataBytes == null) throw new InvalidDataException("No data chunk before the end of the file in " + fileTitle); return new WaveData(format, dataBytes); } } }