diff --git a/AudioAnalysis.sln.DotSettings b/AudioAnalysis.sln.DotSettings index 0664e38ad..5cadf81a8 100644 --- a/AudioAnalysis.sln.DotSettings +++ b/AudioAnalysis.sln.DotSettings @@ -300,6 +300,7 @@ True True True + True True True True diff --git a/src/Acoustics.Shared/Acoustics.Shared.csproj b/src/Acoustics.Shared/Acoustics.Shared.csproj index 123de157e..642a851b3 100644 --- a/src/Acoustics.Shared/Acoustics.Shared.csproj +++ b/src/Acoustics.Shared/Acoustics.Shared.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 Acoustics.Shared @@ -28,6 +28,7 @@ + diff --git a/src/Acoustics.Shared/Extensions/ArrayExtensions.cs b/src/Acoustics.Shared/Extensions/ArrayExtensions.cs index 04de278b0..21c844ea4 100644 --- a/src/Acoustics.Shared/Extensions/ArrayExtensions.cs +++ b/src/Acoustics.Shared/Extensions/ArrayExtensions.cs @@ -10,7 +10,12 @@ // ReSharper disable once CheckNamespace namespace System { + //using MoreLinq; + using static MoreLinq.Extensions.RepeatExtension; + using System.Collections.Generic; using System.Diagnostics; + using System.Linq; + using Acoustics.Shared.Extensions; public static class ArrayExtensions { @@ -105,6 +110,43 @@ public static T[] Print(this T[] array) return array; } + /// + /// Prints a multi-dimensional matrix as a C# literal. + /// + /// Assumes all ranks have a lower bound of zero. + /// Cast element items to T before toString is called. + /// The source array to print. + public static string PrintAsLiteral(this Array array) + { + var dimensions = Enumerable.Range(0, array.Rank); + var sizes = dimensions.Select(array.GetLength).ToArray(); + //var dimensionsWithSize = dimensions.Zip(sizes); + + var last = Enumerable.Range(0, sizes[^1]).ToArray(); + + // the last dimension we iterate across to generate the literal values + var result = sizes[..^1] + .Select(s => Enumerable.Range(0, s)) + .MultiCartesian(FormatValue) + .Join(", ") + .WordWrap(leftPadding: 4, splitOn: "},", keepSplit: true); + + return @$"{{ + {result} + }}"; + + string FormatValue(IEnumerable indices) + { + var depth = sizes.Length; + var lineDepth = depth - 1; + var start = "{ ".Repeat(lineDepth).Join(); + var end = " }".Repeat(lineDepth).Join(); + var value = last.Select(x => (T)array.GetValue(indices.Append(x).ToArray())).Join(", "); + + return start + value + end; + } + } + /// /// Compares two arrays, matching each element in order using the default Equals method for the array type T. /// diff --git a/src/Acoustics.Shared/Extensions/CartesianExtension.cs b/src/Acoustics.Shared/Extensions/CartesianExtension.cs new file mode 100644 index 000000000..f0c17a490 --- /dev/null +++ b/src/Acoustics.Shared/Extensions/CartesianExtension.cs @@ -0,0 +1,77 @@ +// +// All code in this file and all associated files are the copyright and property of the QUT Ecoacoustics Research Group (formerly MQUTeR, and formerly QUT Bioacoustics Research Group). +// + +namespace Acoustics.Shared.Extensions +{ + using System; + using System.Collections.Generic; + using System.Linq; + using MoreLinq.Extensions; + + /// + /// Extensions to the MoreLinq.Cartesian function. + /// + public static class CartesianExtension + { + /// + /// Returns the Cartesian product of multiple sequences by combining each element of every set with every other element + /// and applying the user-defined projection to the pair. + /// + /// The type of the elements of . + /// The type of the elements of the result sequence. + /// The sequence of sequences of element.s + /// A projection function that combines elements from both sequences. + /// A sequence representing the Cartesian product of the source sequences. + public static IEnumerable MultiCartesian( + this IEnumerable> enumerables, + Func, TResult> resultSelector) + { + if (enumerables == null) + { + throw new ArgumentNullException(nameof(enumerables)); + } + + if (resultSelector == null) + { + throw new ArgumentNullException(nameof(resultSelector)); + } + + var enumerators = enumerables + .Select(e => e?.GetEnumerator() ?? throw new ArgumentException("One of the enumerables is null")) + .Pipe(e => e.MoveNext()) + .ToArray(); + + do + { + yield return resultSelector(enumerators.Select(e => e.Current)); + } while (MoveNext()); + + foreach (var enumerator in enumerators) + { + enumerator.Dispose(); + } + + bool MoveNext() + { + for (var i = enumerators.Length - 1; i >= 0; i--) + { + if (enumerators[i].MoveNext()) + { + return true; + } + + if (i == 0) + { + continue; + } + + enumerators[i].Reset(); + enumerators[i].MoveNext(); + } + + return false; + } + } + } +} diff --git a/src/Acoustics.Shared/Extensions/ExtensionsString.cs b/src/Acoustics.Shared/Extensions/ExtensionsString.cs index d13427a81..e2438217b 100644 --- a/src/Acoustics.Shared/Extensions/ExtensionsString.cs +++ b/src/Acoustics.Shared/Extensions/ExtensionsString.cs @@ -203,13 +203,15 @@ public static string Truncate(this string text, int length, string ellipsis, boo return text + ellipsis; } - public static string WordWrap(this string text, int wrapThreshold = 120, int leftPadding = 0) + public static string WordWrap(this string text, int wrapThreshold = 120, int leftPadding = 0, string splitOn = " ", bool keepSplit = false) { if (string.IsNullOrEmpty(text)) { return text; } + int splitLength = splitOn.Length; + string leftPad = string.Empty.PadRight(leftPadding); // wrap lines @@ -229,16 +231,16 @@ public static string WordWrap(this string text, int wrapThreshold = 120, int lef while (currentLine.Length > wrapThreshold) { - int splitPoint = currentLine.Substring(0, wrapThreshold).LastIndexOf(' '); + int splitPoint = currentLine.Substring(0, wrapThreshold).LastIndexOf(splitOn); if (splitPoint < 0) { splitPoint = wrapThreshold; // cuts through a word } - result.AppendLine(leftPad + currentLine.Substring(0, splitPoint)); + result.AppendLine(leftPad + currentLine.Substring(0, splitPoint + (keepSplit ? splitLength : 0))); - currentLine = currentLine.Substring(splitPoint + 1); + currentLine = currentLine.Substring(splitPoint + splitLength); } if (currentLine.IsNotWhitespace()) diff --git a/src/AnalysisPrograms/SpectrogramGenerator/SpectrogramGenerator.Core.cs b/src/AnalysisPrograms/SpectrogramGenerator/SpectrogramGenerator.Core.cs index 7f6482b92..7a03e682c 100644 --- a/src/AnalysisPrograms/SpectrogramGenerator/SpectrogramGenerator.Core.cs +++ b/src/AnalysisPrograms/SpectrogramGenerator/SpectrogramGenerator.Core.cs @@ -478,7 +478,7 @@ public static Image GetOctaveScaleSpectrogram( //TimeSpan xAxisPixelDuration = TimeSpan.FromSeconds(sgConfig.WindowStep / (double)sgConfig.SampleRate); //var labelInterval = TimeSpan.FromSeconds(5); //image = BaseSonogram.FrameSonogram(image, titleBar, startTime, xAxisTicInterval, xAxisPixelDuration, labelInterval); - image = octaveScaleGram.GetImageFullyAnnotated(image, title, freqScale.GridLineLocations); + image = octaveScaleGram.GetImageFullyAnnotated(image, title, freqScale.GridLineLocations, ImageTags[OctaveScaleSpectrogram]); return image; } @@ -497,8 +497,8 @@ public static Image GetRibbonSpectrograms( var imageList = new List> { image2, spacer, image1 }; var combinedImage = ImageTools.CombineImagesVertically(imageList); - var title = "RIBBON SPECTROGRAMS-Linear32 & Octave20: " + sourceRecordingName; - var image = octaveScaleGram.GetImageFullyAnnotated(combinedImage, title, null); + var title = "RIBBON SPECTROGRAMS-Linear32 & Octave19: " + sourceRecordingName; + var image = octaveScaleGram.GetImageFullyAnnotated(combinedImage, title, null, ImageTags[RibbonSpectrogram]); return image; } diff --git a/tests/Acoustics.Test/AnalysisPrograms/SpectrogramGenerator/SpectrogramGeneratorTests.cs b/tests/Acoustics.Test/AnalysisPrograms/SpectrogramGenerator/SpectrogramGeneratorTests.cs index 4dfeb867b..02dc720ac 100644 --- a/tests/Acoustics.Test/AnalysisPrograms/SpectrogramGenerator/SpectrogramGeneratorTests.cs +++ b/tests/Acoustics.Test/AnalysisPrograms/SpectrogramGenerator/SpectrogramGeneratorTests.cs @@ -47,7 +47,7 @@ public class SpectrogramGeneratorTests : GeneratedImageTest { SpectrogramImageType.AmplitudeSpectrogramLocalContrastNormalization, SpectrogramAmplitude }, }; - private static readonly Func Name = x => x.Select(x => (int)x).Join("_"); + private static readonly Func Name = x => x.Select(imageType => (int)imageType).Join("_"); public SpectrogramGeneratorTests() @@ -98,7 +98,7 @@ public void TestAudio2Sonogram() [DynamicData(nameof(AllCombinations), DynamicDataDisplayName = nameof(AllCombinationsTestName))] public void TestAudio2SonogramCombinations(SpectrogramImageType[] images) { - const int OneSecondWidth = 24; + const int oneSecondWidth = 24; var testFile = PathHelper.ResolveAsset("1s_silence.wav"); var config = new SpectrogramGeneratorConfig() @@ -108,17 +108,12 @@ public void TestAudio2SonogramCombinations(SpectrogramImageType[] images) var result = GenerateSpectrogramImages(testFile, config, null); - // save image for debugging purposes - //var flag = images.Aggregate("", (seed, x) => $"{seed}_{(int)x}"); - //var path = this.TestOutputDirectory.CombineFile($"audio2sonogram_{flag}.png"); - //result.CompositeImage.Save(path); - this.ActualImage = result.CompositeImage; this.ExtraName = Name(images); // get expected height var expectedHeight = images.Select(imageType => All[imageType]).Sum(); - Assert.That.ImageIsSize(OneSecondWidth, expectedHeight, this.ActualImage); + Assert.That.ImageIsSize(oneSecondWidth, expectedHeight, this.ActualImage); // ensure images are in correct order int y = 0; diff --git a/tests/Acoustics.Test/AudioAnalysisTools/DSP/FrequencyScaleTests.cs b/tests/Acoustics.Test/AudioAnalysisTools/DSP/FrequencyScaleTests.cs index 2589d3fe6..e30b8298c 100644 --- a/tests/Acoustics.Test/AudioAnalysisTools/DSP/FrequencyScaleTests.cs +++ b/tests/Acoustics.Test/AudioAnalysisTools/DSP/FrequencyScaleTests.cs @@ -6,6 +6,7 @@ namespace Acoustics.Test.AudioAnalysisTools.DSP { using System; using System.Collections.Generic; + using System.Diagnostics; using System.IO; using Acoustics.Test.TestHelpers; using global::AudioAnalysisTools.DSP; @@ -622,66 +623,52 @@ public void OctaveFrequencyScale1() var image = amplitudeSpectrogram.GetImageFullyAnnotated(amplitudeSpectrogram.GetImage(), "SPECTROGRAM: " + fst.ToString(), freqScale.GridLineLocations); image.Save(outputImagePath); - // NOTE: After fixing bugs in Octave Scale code, the following expected BinBounds is no longer correct. - // Instead check size and some locations as below. - + //string binLiteral = freqScale.BinBounds.PrintAsLiteral(); #pragma warning disable SA1500 // Braces for multi-line statements should not share line var expectedBinBounds = new[,] { - { 0, 0 }, { 1, 3 }, { 2, 5 }, { 3, 8 }, { 4, 11 }, { 5, 13 }, { 6, 16 }, { 7, 19 }, { 8, 22 }, - { 9, 24 }, { 10, 27 }, { 11, 30 }, { 12, 32 }, { 13, 35 }, { 14, 38 }, { 15, 40 }, { 16, 43 }, - { 17, 46 }, { 18, 48 }, { 19, 51 }, { 20, 54 }, { 21, 57 }, { 22, 59 }, { 23, 62 }, { 24, 65 }, - { 25, 67 }, { 26, 70 }, { 27, 73 }, { 28, 75 }, { 29, 78 }, { 30, 81 }, { 31, 83 }, { 32, 86 }, - { 33, 89 }, { 34, 92 }, { 35, 94 }, { 36, 97 }, { 37, 100 }, { 38, 102 }, { 39, 105 }, { 40, 108 }, - { 41, 110 }, { 42, 113 }, { 43, 116 }, { 44, 118 }, { 45, 121 }, { 46, 124 }, { 47, 127 }, { 48, 129 }, - { 49, 132 }, { 50, 135 }, { 51, 137 }, { 52, 140 }, { 53, 143 }, { 55, 148 }, { 56, 151 }, { 57, 153 }, - { 58, 156 }, { 59, 159 }, { 61, 164 }, { 62, 167 }, { 63, 170 }, { 65, 175 }, { 66, 178 }, { 68, 183 }, - { 69, 186 }, { 71, 191 }, { 72, 194 }, { 74, 199 }, { 75, 202 }, { 77, 207 }, { 79, 213 }, { 80, 215 }, - { 82, 221 }, { 84, 226 }, { 86, 231 }, { 88, 237 }, { 89, 240 }, { 91, 245 }, { 93, 250 }, { 95, 256 }, - { 97, 261 }, { 100, 269 }, { 102, 275 }, { 104, 280 }, { 106, 285 }, { 109, 293 }, { 111, 299 }, - { 113, 304 }, { 116, 312 }, { 118, 318 }, { 121, 326 }, { 124, 334 }, { 126, 339 }, { 129, 347 }, - { 132, 355 }, { 135, 363 }, { 138, 371 }, { 141, 380 }, { 144, 388 }, { 147, 396 }, { 150, 404 }, - { 153, 412 }, { 157, 423 }, { 160, 431 }, { 164, 441 }, { 167, 450 }, { 171, 460 }, { 175, 471 }, - { 178, 479 }, { 182, 490 }, { 186, 501 }, { 190, 511 }, { 194, 522 }, { 199, 536 }, { 203, 546 }, - { 208, 560 }, { 212, 571 }, { 217, 584 }, { 221, 595 }, { 226, 608 }, { 231, 622 }, { 236, 635 }, - { 241, 649 }, { 247, 665 }, { 252, 678 }, { 258, 694 }, { 263, 708 }, { 269, 724 }, { 275, 740 }, - { 281, 756 }, { 287, 773 }, { 293, 789 }, { 300, 807 }, { 306, 824 }, { 313, 842 }, { 320, 861 }, - { 327, 880 }, { 334, 899 }, { 341, 918 }, { 349, 939 }, { 356, 958 }, { 364, 980 }, { 372, 1001 }, - { 380, 1023 }, { 388, 1044 }, { 397, 1069 }, { 406, 1093 }, { 415, 1117 }, { 424, 1141 }, { 433, 1165 }, - { 442, 1190 }, { 452, 1217 }, { 462, 1244 }, { 472, 1270 }, { 482, 1297 }, { 493, 1327 }, { 504, 1357 }, - { 515, 1386 }, { 526, 1416 }, { 537, 1445 }, { 549, 1478 }, { 561, 1510 }, { 573, 1542 }, { 586, 1577 }, - { 599, 1612 }, { 612, 1647 }, { 625, 1682 }, { 639, 1720 }, { 653, 1758 }, { 667, 1795 }, { 682, 1836 }, - { 697, 1876 }, { 712, 1916 }, { 728, 1960 }, { 744, 2003 }, { 760, 2046 }, { 776, 2089 }, { 793, 2134 }, - { 811, 2183 }, { 829, 2231 }, { 847, 2280 }, { 865, 2328 }, { 884, 2379 }, { 903, 2431 }, { 923, 2484 }, - { 943, 2538 }, { 964, 2595 }, { 985, 2651 }, { 1007, 2710 }, { 1029, 2770 }, { 1051, 2829 }, - { 1074, 2891 }, { 1098, 2955 }, { 1122, 3020 }, { 1146, 3085 }, { 1172, 3155 }, { 1197, 3222 }, - { 1223, 3292 }, { 1250, 3365 }, { 1278, 3440 }, { 1305, 3513 }, { 1334, 3591 }, { 1363, 3669 }, - { 1393, 3749 }, { 1424, 3833 }, { 1455, 3916 }, { 1487, 4002 }, { 1519, 4089 }, { 1552, 4177 }, - { 1586, 4269 }, { 1621, 4363 }, { 1657, 4460 }, { 1693, 4557 }, { 1730, 4657 }, { 1768, 4759 }, - { 1806, 4861 }, { 1846, 4969 }, { 1886, 5076 }, { 1928, 5190 }, { 1970, 5303 }, { 2013, 5418 }, - { 2057, 5537 }, { 2102, 5658 }, { 2148, 5782 }, { 2195, 5908 }, { 2243, 6037 }, { 2292, 6169 }, - { 2343, 6307 }, { 2394, 6444 }, { 2446, 6584 }, { 2500, 6729 }, { 2555, 6877 }, { 2610, 7025 }, - { 2668, 7181 }, { 2726, 7337 }, { 2786, 7499 }, { 2847, 7663 }, { 2909, 7830 }, { 2973, 8002 }, - { 3038, 8177 }, { 3104, 8355 }, { 3172, 8538 }, { 3242, 8726 }, { 3313, 8917 }, { 3385, 9111 }, - { 3459, 9310 }, { 3535, 9515 }, { 3612, 9722 }, { 3691, 9935 }, { 3772, 10153 }, { 3855, 10376 }, - { 3939, 10602 }, { 4026, 10837 }, { 4095, 11022 }, - { 4095, 11022 }, + { 0, 0 }, { 1, 1 }, { 2, 3 }, { 3, 4 }, { 4, 5 }, { 5, 7 }, { 6, 8 }, { 7, 9 }, { 8, 11 }, + { 9, 12 }, { 10, 13 }, { 11, 15 }, { 12, 16 }, { 13, 17 }, { 14, 19 }, { 15, 20 }, { 16, 22 }, + { 17, 23 }, { 18, 24 }, { 19, 26 }, { 20, 27 }, { 21, 28 }, { 22, 30 }, { 23, 31 }, { 24, 32 }, + { 25, 34 }, { 26, 35 }, { 27, 36 }, { 28, 38 }, { 29, 39 }, { 30, 40 }, { 31, 42 }, { 32, 43 }, + { 33, 44 }, { 34, 46 }, { 35, 47 }, { 36, 48 }, { 37, 50 }, { 38, 51 }, { 39, 52 }, { 40, 54 }, + { 41, 55 }, { 42, 57 }, { 43, 58 }, { 44, 59 }, { 45, 61 }, { 46, 62 }, { 47, 63 }, { 48, 65 }, + { 49, 66 }, { 50, 67 }, { 51, 69 }, { 52, 70 }, { 53, 71 }, { 54, 73 }, { 55, 74 }, { 56, 75 }, + { 57, 77 }, { 58, 78 }, { 59, 79 }, { 60, 81 }, { 61, 82 }, { 62, 83 }, { 63, 85 }, { 64, 86 }, + { 65, 87 }, { 66, 89 }, { 67, 90 }, { 68, 92 }, { 69, 93 }, { 70, 94 }, { 71, 96 }, { 72, 97 }, + { 73, 98 }, { 74, 100 }, { 75, 101 }, { 76, 102 }, { 77, 104 }, { 78, 105 }, { 79, 106 }, { 80, 108 }, + { 81, 109 }, { 82, 110 }, { 83, 112 }, { 84, 113 }, { 85, 114 }, { 86, 116 }, { 87, 117 }, { 88, 118 }, + { 89, 120 }, { 90, 121 }, { 91, 122 }, { 92, 124 }, { 93, 125 }, { 96, 129 }, { 99, 133 }, + { 101, 136 }, { 104, 140 }, { 107, 144 }, { 110, 148 }, { 113, 152 }, { 116, 156 }, { 120, 161 }, + { 123, 166 }, { 127, 171 }, { 130, 175 }, { 134, 180 }, { 137, 184 }, { 141, 190 }, { 145, 195 }, + { 149, 201 }, { 153, 206 }, { 158, 213 }, { 162, 218 }, { 167, 225 }, { 171, 230 }, { 176, 237 }, + { 181, 244 }, { 186, 250 }, { 191, 257 }, { 197, 265 }, { 202, 272 }, { 208, 280 }, { 214, 288 }, + { 220, 296 }, { 226, 304 }, { 232, 312 }, { 239, 322 }, { 246, 331 }, { 253, 340 }, { 260, 350 }, + { 267, 359 }, { 274, 369 }, { 282, 380 }, { 290, 390 }, { 298, 401 }, { 306, 412 }, { 315, 424 }, + { 324, 436 }, { 333, 448 }, { 342, 460 }, { 352, 474 }, { 362, 487 }, { 372, 501 }, { 382, 514 }, + { 393, 529 }, { 404, 544 }, { 416, 560 }, { 427, 575 }, { 439, 591 }, { 452, 608 }, { 464, 624 }, + { 477, 642 }, { 491, 661 }, { 505, 680 }, { 519, 698 }, { 533, 717 }, { 548, 738 }, { 564, 759 }, + { 579, 779 }, { 596, 802 }, { 612, 824 }, { 630, 848 }, { 647, 871 }, { 666, 896 }, { 684, 921 }, + { 703, 946 }, { 723, 973 }, { 744, 1001 }, { 764, 1028 }, { 786, 1058 }, { 808, 1087 }, { 831, 1118 }, + { 854, 1149 }, { 878, 1182 }, { 903, 1215 }, { 928, 1249 }, { 954, 1284 }, { 981, 1320 }, + { 1009, 1358 }, + { 1037, 1396 }, { 1066, 1435 }, { 1096, 1475 }, { 1127, 1517 }, { 1158, 1558 }, { 1191, 1603 }, + { 1224, 1647 }, { 1259, 1694 }, { 1294, 1741 }, { 1331, 1791 }, { 1368, 1841 }, { 1406, 1892 }, + { 1446, 1946 }, { 1487, 2001 }, { 1528, 2056 }, { 1571, 2114 }, { 1615, 2174 }, { 1661, 2235 }, + { 1708, 2299 }, { 1756, 2363 }, { 1805, 2429 }, { 1856, 2498 }, { 1908, 2568 }, { 1961, 2639 }, + { 2017, 2715 }, { 2073, 2790 }, { 2131, 2868 }, { 2191, 2949 }, { 2253, 3032 }, { 2316, 3117 }, + { 2381, 3204 }, { 2448, 3295 }, { 2517, 3387 }, { 2588, 3483 }, { 2661, 3581 }, { 2735, 3681 }, + { 2812, 3784 }, { 2891, 3891 }, { 2973, 4001 }, { 3056, 4113 }, { 3142, 4229 }, { 3230, 4347 }, + { 3321, 4469 }, { 3415, 4596 }, { 3511, 4725 }, { 3609, 4857 }, { 3711, 4994 }, { 3815, 5134 }, + { 3922, 5278 }, { 4033, 5428 }, { 4146, 5580 }, { 4262, 5736 }, { 4382, 5897 }, { 4505, 6063 }, + { 4632, 6234 }, { 4762, 6409 }, { 4896, 6589 }, { 5034, 6775 }, { 5175, 6965 }, { 5321, 7161 }, + { 5470, 7362 }, { 5624, 7569 }, { 5782, 7782 }, { 5945, 8001 }, { 6112, 8226 }, { 6284, 8457 }, + { 6460, 8694 }, { 6642, 8939 }, { 6829, 9191 }, { 7021, 9449 }, { 7218, 9714 }, { 7421, 9987 }, + { 7630, 10269 }, { 7844, 10557 }, { 8191, 11024 }, }; #pragma warning restore SA1500 // Braces for multi-line statements should not share line - //Assert.That.MatricesAreEqual(expectedBinBounds, freqScale.BinBounds); - - Assert.AreEqual(255, freqScale.BinBounds.GetLength(0)); - Assert.AreEqual(23, freqScale.BinBounds[23, 0]); - Assert.AreEqual(31, freqScale.BinBounds[23, 1]); - Assert.AreEqual(46, freqScale.BinBounds[46, 0]); - Assert.AreEqual(62, freqScale.BinBounds[46, 1]); - Assert.AreEqual(113, freqScale.BinBounds[100, 0]); - Assert.AreEqual(152, freqScale.BinBounds[100, 1]); - Assert.AreEqual(246, freqScale.BinBounds[128, 0]); - Assert.AreEqual(331, freqScale.BinBounds[128, 1]); - Assert.AreEqual(8191, freqScale.BinBounds[254, 0]); - Assert.AreEqual(11024, freqScale.BinBounds[254, 1]); + Assert.That.MatricesAreEqual(expectedBinBounds, freqScale.BinBounds); // Check that freqScale.GridLineLocations are correct var expected = new[,] diff --git a/tests/Acoustics.Test/TestHelpers/Random.cs b/tests/Acoustics.Test/TestHelpers/Random.cs index d977c0cfe..8ade2a819 100644 --- a/tests/Acoustics.Test/TestHelpers/Random.cs +++ b/tests/Acoustics.Test/TestHelpers/Random.cs @@ -13,7 +13,7 @@ internal static class Random { public static System.Random GetRandom(int? seed = null) { - seed = seed ?? Environment.TickCount; + seed ??= Environment.TickCount; Trace.WriteLine("\n\nRandom seed used: " + seed.Value); LoggedConsole.WriteWarnLine($"Random seed: {seed}");