ResamplerTests.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. using NUnit.Framework;
  2. using Ryujinx.Audio.Renderer.Dsp;
  3. using Ryujinx.Audio.Renderer.Parameter;
  4. using Ryujinx.Audio.Renderer.Server.Upsampler;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Runtime.CompilerServices;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. namespace Ryujinx.Tests.Audio.Renderer.Dsp
  13. {
  14. class ResamplerTests
  15. {
  16. [Test]
  17. [TestCase(VoiceInParameter.SampleRateConversionQuality.Low)]
  18. [TestCase(VoiceInParameter.SampleRateConversionQuality.Default)]
  19. [TestCase(VoiceInParameter.SampleRateConversionQuality.High)]
  20. public void TestResamplerConsistencyUpsampling(VoiceInParameter.SampleRateConversionQuality quality)
  21. {
  22. DoResamplingTest(44100, 48000, quality);
  23. }
  24. [Test]
  25. [TestCase(VoiceInParameter.SampleRateConversionQuality.Low)]
  26. [TestCase(VoiceInParameter.SampleRateConversionQuality.Default)]
  27. [TestCase(VoiceInParameter.SampleRateConversionQuality.High)]
  28. public void TestResamplerConsistencyDownsampling(VoiceInParameter.SampleRateConversionQuality quality)
  29. {
  30. DoResamplingTest(48000, 44100, quality);
  31. }
  32. /// <summary>
  33. /// Generates a 1-second sine wave sample at input rate, resamples it to output rate, and
  34. /// ensures that it resampled at the expected rate with no discontinuities
  35. /// </summary>
  36. /// <param name="inputRate">The input sample rate to test</param>
  37. /// <param name="outputRate">The output sample rate to test</param>
  38. /// <param name="quality">The resampler quality to use</param>
  39. private static void DoResamplingTest(int inputRate, int outputRate, VoiceInParameter.SampleRateConversionQuality quality)
  40. {
  41. float inputSampleRate = (float)inputRate;
  42. float outputSampleRate = (float)outputRate;
  43. int inputSampleCount = inputRate;
  44. int outputSampleCount = outputRate;
  45. short[] inputBuffer = new short[inputSampleCount + 100]; // add some safety buffer at the end
  46. float[] outputBuffer = new float[outputSampleCount + 100];
  47. for (int sample = 0; sample < inputBuffer.Length; sample++)
  48. {
  49. // 440 hz sine wave with amplitude = 0.5f at input sample rate
  50. inputBuffer[sample] = (short)(32767 * MathF.Sin((440 / inputSampleRate) * (float)sample * MathF.PI * 2f) * 0.5f);
  51. }
  52. float fraction = 0;
  53. ResamplerHelper.Resample(
  54. outputBuffer.AsSpan(),
  55. inputBuffer.AsSpan(),
  56. inputSampleRate / outputSampleRate,
  57. ref fraction,
  58. outputSampleCount,
  59. quality,
  60. false);
  61. float[] expectedOutput = new float[outputSampleCount];
  62. float sumDifference = 0;
  63. int delay = quality switch
  64. {
  65. VoiceInParameter.SampleRateConversionQuality.High => 3,
  66. VoiceInParameter.SampleRateConversionQuality.Default => 1,
  67. _ => 0
  68. };
  69. for (int sample = 0; sample < outputSampleCount; sample++)
  70. {
  71. outputBuffer[sample] /= 32767;
  72. // 440 hz sine wave with amplitude = 0.5f at output sample rate
  73. expectedOutput[sample] = MathF.Sin((440 / outputSampleRate) * (float)(sample + delay) * MathF.PI * 2f) * 0.5f;
  74. float thisDelta = Math.Abs(expectedOutput[sample] - outputBuffer[sample]);
  75. // Ensure no discontinuities
  76. Assert.IsTrue(thisDelta < 0.1f);
  77. sumDifference += thisDelta;
  78. }
  79. sumDifference = sumDifference / (float)outputSampleCount;
  80. // Expect the output to be 99% similar to the expected resampled sine wave
  81. Assert.IsTrue(sumDifference < 0.01f);
  82. }
  83. }
  84. }