Audacity 3.2.0
StaffPadTimeAndPitchTest.cpp
Go to the documentation of this file.
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*!********************************************************************
3
4 Audacity: A Digital Audio Editor
5
6 StaffPadTimeAndPitchTest.cpp
7
8 Matthieu Hodgkinson
9
10**********************************************************************/
12#include "AudioContainer.h"
15#include "WavFileIO.h"
16
17#include <catch2/catch.hpp>
18
19using namespace std::literals::string_literals;
20using namespace std::literals::chrono_literals;
21
22TEST_CASE("StaffPadTimeAndPitch")
23{
24 SECTION("Smoke test")
25 {
26 using TestParameter =
27 std::pair<std::string, std::optional<std::chrono::seconds>>;
28 const auto [filenameStem, upTo] = GENERATE(
29 TestParameter { "AudacitySpectral", std::nullopt },
30 TestParameter { "FifeAndDrumsStereo", 3s });
31 const auto inputPath = std::string(CMAKE_SOURCE_DIR) + "/tests/samples/" +
32 filenameStem + ".wav";
33
34 std::optional<std::string> outputDir;
35 // Uncomment this if you want to look at the output locally.
36 // outputDir = "C:/Users/saint/Downloads/StaffPadTimeAndPitchTestOut";
37
38 std::vector<std::vector<float>> input;
39 AudioFileInfo info;
40 REQUIRE(WavFileIO::Read(inputPath, input, info, upTo));
41 for (const auto pitchRatio : std::vector<std::pair<int, int>> {
42 { 4, 5 }, // major 3rd down
43 { 1, 1 }, // no shift
44 { 5, 4 }, // major 3rd up
45 })
46 {
47 const auto pr =
48 static_cast<double>(pitchRatio.first) / pitchRatio.second;
49 for (const auto timeRatio : std::vector<std::pair<int, int>> {
50 { 1, 2 },
51 { 1, 1 },
52 { 2, 1 },
53 })
54 {
55 const auto tr =
56 static_cast<double>(timeRatio.first) / timeRatio.second;
57 const auto numOutputFrames =
58 static_cast<size_t>(info.numFrames * tr);
59 AudioContainer container(numOutputFrames, info.numChannels);
61 params.timeRatio = tr;
62 params.pitchRatio = pr;
63 TimeAndPitchRealSource src(input);
65 info.sampleRate, info.numChannels, src, std::move(params));
66 constexpr size_t blockSize = 1234u;
67 auto offset = 0u;
68 while (offset < numOutputFrames)
69 {
70 std::vector<float*> offsetBuffers(info.numChannels);
71 for (auto i = 0u; i < info.numChannels; ++i)
72 offsetBuffers[i] = container.channelPointers[i] + offset;
73 const auto numToRead =
74 std::min(numOutputFrames - offset, blockSize);
75 sut.GetSamples(offsetBuffers.data(), numToRead);
76 offset += numToRead;
77 }
78
79 if (outputDir)
80 {
81 const auto filename = filenameStem + "_t"s +
82 std::to_string(timeRatio.first) + "-" +
83 std::to_string(timeRatio.second) + "_p" +
84 std::to_string(pitchRatio.first) + "-" +
85 std::to_string(pitchRatio.second) + ".wav";
86 const auto outputPath = *outputDir + "/" + filename;
87 REQUIRE(WavFileIO::Write(
88 outputPath, container.channelVectors, info.sampleRate));
89 }
90 }
91 }
92 }
93
94 SECTION("Not specifying time or pitch or ratio yields bit-exact results")
95 {
96 // Although this is no hard-proof, a bit-exact output is a strong evidence
97 // that no processing happens if no time or pitch ratio is specified,
98 // which is what we want.
99
100 const auto inputPath =
101 std::string(CMAKE_SOURCE_DIR) + "/tests/samples/AudacitySpectral.wav";
102 std::vector<std::vector<float>> input;
103 AudioFileInfo info;
104 REQUIRE(WavFileIO::Read(inputPath, input, info));
105 AudioContainer container(info.numFrames, info.numChannels);
107 TimeAndPitchRealSource src(input);
109 info.sampleRate, info.numChannels, src, std::move(params));
110 sut.GetSamples(container.Get(), info.numFrames);
111 // Calling REQUIRE(container.channelVectors == input) directly for large
112 // vectors might be rough on stdout in case of an error printout ...
113 const auto outputEqualsInput = container.channelVectors == input;
114 REQUIRE(outputEqualsInput);
115 }
116
117 SECTION("Extreme stretch ratios")
118 {
119 constexpr auto originalDuration = 60.; // 1 minute
120 constexpr auto targetDuration = 1. / 44100; // 1 sample
121 constexpr auto superSmallRatio = targetDuration / originalDuration;
122 constexpr auto requestedNumSamples =
123 1; // ... a single sample, but which is the condensed form of one
124 // minute of audio :D
125 constexpr auto numChannels = 1;
127 AudioContainer container(requestedNumSamples, numChannels);
129 params.timeRatio = superSmallRatio;
130 StaffPadTimeAndPitch sut(44100, numChannels, src, std::move(params));
131 sut.GetSamples(
132 container.Get(),
133 requestedNumSamples); // This is just not supposed to hang.
134 }
135}
int min(int a, int b)
EffectDistortionSettings params
Definition: Distortion.cpp:77
for(int ii=0, nn=names.size();ii< nn;++ii)
TEST_CASE("StaffPadTimeAndPitch")
void GetSamples(float *const *, size_t) override
std::vector< float * > channelPointers
std::vector< std::vector< float > > channelVectors
float *const * Get() const