public unsafe void SampleBlockConversions() { SampleBlock reference16Bit; using (MediaFoundationReader reference16BitReader = new MediaFoundationReader(TestConstant.ReferenceFilePath16Bit)) { byte[] buffer16Bit = new byte[reference16BitReader.Length]; int bytesRead = reference16BitReader.Read(buffer16Bit, 0, buffer16Bit.Length); reference16Bit = new SampleBlock(buffer16Bit, bytesRead, SampleTypeExtensions.FromBitsPerSample(reference16BitReader.WaveFormat.BitsPerSample)); } SampleBlock reference24Bit; using (MediaFoundationReader reference24BitReader = new MediaFoundationReader(TestConstant.ReferenceFilePath24Bit)) { byte[] buffer24Bit = new byte[reference24BitReader.Length]; int bytesRead = reference24BitReader.Read(buffer24Bit, 0, buffer24Bit.Length); reference24Bit = new SampleBlock(buffer24Bit, bytesRead, SampleTypeExtensions.FromBitsPerSample(reference24BitReader.WaveFormat.BitsPerSample)); } Assert.IsTrue(reference16Bit.Int16Samples == reference24Bit.SamplesInUse); SampleBlock reference16BitAsDouble = reference16Bit.ConvertTo(SampleType.Double); SampleBlock reference16BitAsQ31 = reference16Bit.ConvertTo(SampleType.Int32); SampleBlock reference24BitAsDouble = reference24Bit.ConvertTo(SampleType.Double); SampleBlock reference24BitAsQ31 = reference24Bit.ConvertTo(SampleType.Int32); Assert.IsTrue(reference16Bit.Int16Samples == reference16BitAsDouble.DoubleSamples); Assert.IsTrue(reference16Bit.Int16Samples == reference16BitAsQ31.Int32Samples); Assert.IsTrue(reference16Bit.Int16Samples == reference24BitAsDouble.DoubleSamples); Assert.IsTrue(reference16Bit.Int16Samples == reference24BitAsQ31.Int32Samples); for (int sample = 0; sample < reference16Bit.Int16Samples; ++sample) { Assert.IsTrue(((int)reference16Bit.Int16s[sample] << TestConstant.ShiftBetween16BitSamplesAndQ31) == reference16BitAsQ31.Int32s[sample]); Assert.IsTrue((int)reference16BitAsDouble.Doubles[sample] == reference16BitAsQ31.Int32s[sample]); Assert.IsTrue((reference24Bit.GetInt24AsInt32(sample) << TestConstant.ShiftBetween24BitSamplesAndQ31) == reference24BitAsQ31.Int32s[sample]); Assert.IsTrue((int)reference24BitAsDouble.Doubles[sample] == reference24BitAsQ31.Int32s[sample]); } }
private unsafe void VerifyWaveFilesEquivalent(string actualFilePath, string expectedFilePath, double expectedToActualScaleFactor, double sampleMatchTolerance, bool verifySampleSize) { // load data in files SampleBlock actual; WaveFormat actualFormat; using (MediaFoundationReader actualReader = new MediaFoundationReader(actualFilePath)) { byte[] buffer = new byte[actualReader.Length]; int bytesRead = actualReader.Read(buffer, 0, buffer.Length); actual = new SampleBlock(buffer, bytesRead, SampleTypeExtensions.FromBitsPerSample(actualReader.WaveFormat.BitsPerSample)); actualFormat = actualReader.WaveFormat; } SampleBlock expected; WaveFormat expectedFormat; using (MediaFoundationReader expectedReader = new MediaFoundationReader(expectedFilePath)) { byte[] buffer = new byte[expectedReader.Length]; int bytesRead = expectedReader.Read(buffer, 0, buffer.Length); expected = new SampleBlock(buffer, bytesRead, SampleTypeExtensions.FromBitsPerSample(expectedReader.WaveFormat.BitsPerSample)); expectedFormat = expectedReader.WaveFormat; } // check data format matches Assert.IsTrue(actual.SamplesInUse == expected.SamplesInUse); if (verifySampleSize) { Assert.IsTrue(actual.SampleType == expected.SampleType); Assert.IsTrue(actualFormat.AverageBytesPerSecond == expectedFormat.AverageBytesPerSecond); Assert.IsTrue(actualFormat.BitsPerSample == expectedFormat.BitsPerSample); Assert.IsTrue(actualFormat.BlockAlign == expectedFormat.BlockAlign); } Assert.IsTrue(actualFormat.Channels == expectedFormat.Channels); Assert.IsTrue(actualFormat.Encoding == expectedFormat.Encoding); Assert.IsTrue(actualFormat.ExtraSize == expectedFormat.ExtraSize); Assert.IsTrue(actualFormat.SampleRate == expectedFormat.SampleRate); double largestMismatch = 0.0; double maxExpectedValue = Math.Pow(2.0, expected.SampleType.BitsPerSample() - 1) - 1; double minExpectedValue = -Math.Pow(2.0, expected.SampleType.BitsPerSample() - 1); double mismatchStandardDevation = 0.0; using (FileStream samplesStream = new FileStream(String.Format("{0} - {1}.csv", Path.GetFileNameWithoutExtension(actualFilePath), Path.GetFileNameWithoutExtension(expectedFilePath)), FileMode.Create)) { using (StreamWriter samplesWriter = new StreamWriter(samplesStream)) { samplesWriter.WriteLine("actual,expected"); int clippedSamples = 0; int mismatchedSamples = 0; int samples = expected.SamplesInUse; for (int sample = 0; sample < samples; ++sample) { // read samples as ints and convert to doubles regardless of sample type in files double actualSample; switch (actual.SampleType) { case SampleType.Int16: actualSample = actual.Int16s[sample]; break; case SampleType.Int24: actualSample = actual.GetInt24AsInt32(sample); break; case SampleType.Int32: actualSample = actual.Int32s[sample]; break; default: throw new NotSupportedException(String.Format("Unhandled sample type {0}.", expected.SampleType)); } actualSample = actualSample / expectedToActualScaleFactor; double expectedSample; switch (expected.SampleType) { case SampleType.Int16: expectedSample = expected.Int16s[sample]; break; case SampleType.Int24: expectedSample = expected.GetInt24AsInt32(sample); break; case SampleType.Int32: expectedSample = expected.Int32s[sample]; break; default: throw new NotSupportedException(String.Format("Unhandled sample type {0}.", expected.SampleType)); } samplesWriter.WriteLine("{0},{1}", actualSample, expectedSample); // it's OK if the expected data is clipped and the actual data isn't if (expectedSample >= maxExpectedValue && actualSample > expectedSample) { ++clippedSamples; continue; } if (expectedSample <= minExpectedValue && actualSample < expectedSample) { ++clippedSamples; continue; } // check samples for equivalence // standard deviation calculation is naive as it assumes the average mismatch is zero double mismatch = Math.Abs(expectedSample - actualSample); mismatchStandardDevation += mismatch * mismatch; if (mismatch > largestMismatch) { largestMismatch = mismatch; } if (mismatch > sampleMatchTolerance) { ++mismatchedSamples; } } mismatchStandardDevation = Math.Sqrt(mismatchStandardDevation / (double)expected.SamplesInUse); this.TestContext.WriteLine("Largest mismatch in samples between {0} and {1} was {2:0.0} with a standard deviation of {3:0.0}.", actualFilePath, expectedFilePath, largestMismatch, mismatchStandardDevation); this.TestContext.WriteLine(">>> {0} samples exceeded threshold of {1:0.0}.", mismatchedSamples, sampleMatchTolerance); Assert.IsTrue(mismatchedSamples == 0, "{0} of {1} ({2:#0.0%}) samples did not match within tolerance {3}.", mismatchedSamples, samples, (double)mismatchedSamples / (double)samples, sampleMatchTolerance); if (verifySampleSize) { Assert.IsTrue(clippedSamples < 0.0001 * samples, "{0} (1:#0.000%) samples were clipped; this is unexpectedly high.", clippedSamples, (double)clippedSamples / (double)samples); } } } // check metadata Tag actualMetadata; using (FileStream inputMetadataStream = new FileStream(actualFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (TagFile inputTagFile = TagFile.Create(new StreamFileAbstraction(inputMetadataStream.Name, inputMetadataStream, inputMetadataStream))) { actualMetadata = inputTagFile.Tag; } } Tag expectedMetadata; using (FileStream outputMetadataStream = new FileStream(expectedFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (TagFile outputTagFile = TagFile.Create(new StreamFileAbstraction(outputMetadataStream.Name, outputMetadataStream, outputMetadataStream))) { expectedMetadata = outputTagFile.Tag; } } Assert.AreEqual(expectedMetadata.Album, actualMetadata.Album, String.Format("Expected artist '{0}' but got '{1}'.", expectedMetadata.Album, actualMetadata.Album)); Assert.AreEqual(expectedMetadata.AmazonId, actualMetadata.AmazonId, String.Format("Expected Amazon ID '{0}' but got '{1}'.", expectedMetadata.AmazonId, actualMetadata.AmazonId)); Assert.AreEqual(expectedMetadata.Conductor, actualMetadata.Conductor, String.Format("Expected conductor '{0}' but got '{1}'.", expectedMetadata.Conductor, actualMetadata.Conductor)); Assert.AreEqual(expectedMetadata.Copyright, actualMetadata.Copyright, String.Format("Expected copyright '{0}' but got '{1}'.", expectedMetadata.Copyright, actualMetadata.Copyright)); Assert.AreEqual(expectedMetadata.Disc, actualMetadata.Disc, String.Format("Expected disc '{0}' but got '{1}'.", expectedMetadata.Disc, actualMetadata.Disc)); Assert.AreEqual(expectedMetadata.DiscCount, actualMetadata.DiscCount, String.Format("Expected disc count '{0}' but got '{1}'.", expectedMetadata.DiscCount, actualMetadata.DiscCount)); Assert.AreEqual(expectedMetadata.Grouping, actualMetadata.Grouping, String.Format("Expected grouping '{0}' but got '{1}'.", expectedMetadata.Grouping, actualMetadata.Grouping)); Assert.AreEqual(expectedMetadata.Lyrics, actualMetadata.Lyrics, String.Format("Expected lyrics '{0}' but got '{1}'.", expectedMetadata.Lyrics, actualMetadata.Lyrics)); Assert.AreEqual(expectedMetadata.JoinedAlbumArtists, actualMetadata.JoinedAlbumArtists, String.Format("Expected artists '{0}' but got '{1}'.", expectedMetadata.JoinedAlbumArtists, actualMetadata.JoinedAlbumArtists)); Assert.AreEqual(expectedMetadata.JoinedComposers, actualMetadata.JoinedComposers, String.Format("Expected composers '{0}' but got '{1}'.", expectedMetadata.JoinedComposers, actualMetadata.JoinedComposers)); Assert.AreEqual(expectedMetadata.JoinedGenres, actualMetadata.JoinedGenres, String.Format("Expected genres '{0}' but got '{1}'.", expectedMetadata.JoinedGenres, actualMetadata.JoinedGenres)); Assert.AreEqual(expectedMetadata.JoinedPerformersSort, actualMetadata.JoinedPerformersSort, String.Format("Expected performers '{0}' but got '{1}'.", expectedMetadata.JoinedPerformersSort, actualMetadata.JoinedPerformersSort)); // Pictures is not checked Assert.AreEqual(expectedMetadata.Title, actualMetadata.Title, String.Format("Expected title '{0}' but got '{1}'.", expectedMetadata.Title, actualMetadata.Title)); Assert.AreEqual(expectedMetadata.Track, actualMetadata.Track, String.Format("Expected track '{0}' but got '{1}'.", expectedMetadata.Track, actualMetadata.Track)); Assert.AreEqual(expectedMetadata.TrackCount, actualMetadata.TrackCount, String.Format("Expected track count '{0}' but got '{1}'.", expectedMetadata.TrackCount, actualMetadata.TrackCount)); Assert.AreEqual(expectedMetadata.Year, actualMetadata.Year, String.Format("Expected year '{0}' but got '{1}'.", expectedMetadata.Year, actualMetadata.Year)); }