Audacity 3.2.0
Namespaces | Functions | Variables
StretchingSequenceTest.cpp File Reference
#include "StretchingSequence.h"
#include "AudioContainer.h"
#include "AudioContainerHelper.h"
#include "FloatVectorClip.h"
#include "MockAudioSegmentFactory.h"
#include "MockPlayableSequence.h"
#include "SampleFormat.h"
#include "WavFileIO.h"
#include <array>
#include <catch2/catch.hpp>
Include dependency graph for StretchingSequenceTest.cpp:

Go to the source code of this file.

Namespaces

namespace  anonymous_namespace{StretchingSequenceTest.cpp}
 

Functions

 TEST_CASE ("StretchingSequence unit tests")
 
 TEST_CASE ("StretchingSequence with real audio")
 

Variables

constexpr auto anonymous_namespace{StretchingSequenceTest.cpp}::sampleRate = 3
 

Function Documentation

◆ TEST_CASE() [1/2]

TEST_CASE ( "StretchingSequence unit tests"  )

Definition at line 31 of file StretchingSequenceTest.cpp.

32{
33 SECTION("Get")
34 {
35 constexpr auto backwards = true;
36 constexpr auto numChannels = 1u;
37
38 SECTION("Samples can be queried backwards")
39 {
40 // Mimic the way a client would use the legacy API to read samples
41 // backwards.
42 // Our sequence : 1s silence, 1s clip, 1s silence, 1s clip.
43 const auto clip1 = std::make_shared<FloatVectorClip>(
44 sampleRate, std::vector<float> { 1.f, 2.f, 3.f }, numChannels);
45 const auto clip3 = std::make_shared<FloatVectorClip>(
46 sampleRate, std::vector<float> { 4.f, 5.f, 6.f }, numChannels);
47 clip1->playStartTime = 1.0;
48 clip3->playStartTime = 3.0;
49 const auto mockSequence =
50 std::make_shared<MockPlayableSequence>(sampleRate, numChannels);
51 const auto sut = StretchingSequence::Create(
52 *mockSequence, ClipConstHolders { clip1, clip3 });
53
54 constexpr auto len = 2;
55 const std::array<std::vector<float>, 6> expected { { { 6.f, 5.f },
56 { 4.f, 0.f },
57 { 0.f, 0.f },
58 { 3.f, 2.f },
59 { 1.f, 0.f },
60 { 0.f, 0.f } } };
61 auto start = 12;
62 for (const auto& expected : expected)
63 {
64 AudioContainer output(len, numChannels);
65 constexpr auto backwards = true;
66 sut->GetFloats(
67 AudioContainerHelper::GetData(output).data(), start, len,
68 backwards);
69 REQUIRE(output.channelVectors[0] == expected);
70 start -= 2;
71 }
72 }
73
74 SECTION("reconstructs segment sequence when expected")
75 {
77 const auto mockSequence =
78 std::make_shared<MockPlayableSequence>(sampleRate, numChannels);
80 *mockSequence, sampleRate, numChannels,
81 std::unique_ptr<AudioSegmentFactoryInterface> { factory });
82 constexpr auto numSamples = 3;
83 constexpr auto numChannels = 1;
84 constexpr auto start = 10; // some random place in the future
85 AudioContainer buffer(numSamples, 1);
86 REQUIRE(sut.GetFloats(
87 AudioContainerHelper::GetData(buffer).data(), start, numSamples,
88 !backwards));
89 // We don't really care about the call count before that.
90 const auto refCount = factory->callCount;
91 // Expected query: no factory call
92 REQUIRE(sut.GetFloats(
93 AudioContainerHelper::GetData(buffer).data(), start + numSamples,
94 numSamples, !backwards));
95 REQUIRE(factory->callCount == refCount);
96 // Repeat the same query: expect a factory call.
97 REQUIRE(sut.GetFloats(
98 AudioContainerHelper::GetData(buffer).data(), start + numSamples,
99 numSamples, !backwards));
100 REQUIRE(factory->callCount == refCount + 1);
101 // Use expected index, but opposite direction: expect a factory call.
102 REQUIRE(sut.GetFloats(
103 AudioContainerHelper::GetData(buffer).data(),
104 start + numSamples * 2, numSamples, backwards));
105 REQUIRE(factory->callCount == refCount + 2);
106 // Now that we're calling backwards, call with expected index: no
107 // factory call.
108 REQUIRE(sut.GetFloats(
109 AudioContainerHelper::GetData(buffer).data(), start + numSamples,
110 numSamples, backwards));
111 REQUIRE(factory->callCount == refCount + 2);
112 }
113 }
114}
std::vector< std::shared_ptr< const ClipInterface > > ClipConstHolders
static RegisteredToolbarFactory factory
static std::vector< T * > GetData(const AudioContainer &container, size_t offset=0u)
static std::shared_ptr< StretchingSequence > Create(const PlayableSequence &, const ClipConstHolders &clips)

References AudioContainer::channelVectors, StretchingSequence::Create(), factory, AudioContainerHelper::GetData(), and anonymous_namespace{StretchingSequenceTest.cpp}::sampleRate.

Here is the call graph for this function:

◆ TEST_CASE() [2/2]

TEST_CASE ( "StretchingSequence with real audio )

Definition at line 116 of file StretchingSequenceTest.cpp.

117{
118 const auto filenameStem = "FifeAndDrumsStereo"s;
119 const auto inputPath =
120 std::string(CMAKE_SOURCE_DIR) + "/tests/samples/" + filenameStem + ".wav";
121
122 std::optional<std::string> outputDir;
123 // Uncomment this if you want to look at the output locally.
124 // outputDir = "C:/Users/saint/Downloads/StaffPadTimeAndPitchTestOut";
125 const auto backwards = GENERATE(false, true);
126
127 SECTION("with one clip")
128 {
129 const auto ratio = GENERATE(0.75, 1.5);
130 std::vector<std::vector<float>> input;
131 AudioFileInfo info;
132 REQUIRE(WavFileIO::Read(inputPath, input, info, 7s));
133 const auto clip =
134 std::make_shared<FloatVectorClip>(info.sampleRate, input);
135 clip->stretchRatio = ratio;
136 const auto mockSequence = std::make_shared<MockPlayableSequence>(
137 info.sampleRate, info.numChannels);
138 const auto sut =
139 StretchingSequence::Create(*mockSequence, ClipConstHolders { clip });
140 const size_t numOutputSamples = clip->stretchRatio * input[0].size() + .5;
141 AudioContainer container(numOutputSamples, input.size());
142 sut->GetFloats(
143 container.channelPointers.data(), backwards ? numOutputSamples : 0,
144 numOutputSamples, backwards);
145 if (outputDir)
146 {
147 const auto filename = "oneclip_"s + filenameStem +
148 (backwards ? "_bwd" : "_fwd") +
149 (ratio < 1. ? "_fast" : "_slow") + ".wav";
150 const auto outputPath = *outputDir + "/" + filename;
151 REQUIRE(WavFileIO::Write(
152 outputPath, container.channelVectors, info.sampleRate));
153 }
154 }
155
156 SECTION("with several clips")
157 {
158 std::vector<std::vector<float>> input;
159 AudioFileInfo info;
160 REQUIRE(WavFileIO::Read(inputPath, input, info, 7s));
161 const auto clip1 =
162 std::make_shared<FloatVectorClip>(info.sampleRate, input);
163 const auto clip2 =
164 std::make_shared<FloatVectorClip>(info.sampleRate, input);
165 clip1->stretchRatio = 0.75;
166 clip2->stretchRatio = 1.5;
167
168 // 1s of silence, clip 1, 2s of silence, clip 2.
169 clip1->playStartTime = 1.;
170 clip2->playStartTime = clip1->GetPlayEndTime() + 2.;
171 const auto totalDuration = clip2->GetPlayEndTime();
172
173 const auto mockSequence =
174 std::make_shared<MockPlayableSequence>(info.sampleRate, 2u);
175 const auto sut = StretchingSequence::Create(
176 *mockSequence, ClipConstHolders { clip1, clip2 });
177 const size_t numOutputSamples =
178 totalDuration * info.sampleRate /*assuming both have same sample rate*/
179 + .5;
180 AudioContainer container(numOutputSamples, 2u);
181 const auto start = backwards ? numOutputSamples : 0u;
182 sut->GetFloats(
183 container.channelPointers.data(), start, numOutputSamples, backwards);
184 if (outputDir)
185 {
186 const auto filename = "manyClips_"s + filenameStem +
187 (backwards ? "_bwd" : "_fwd") + ".wav";
188 const auto outputPath = *outputDir + "/" + filename;
189 REQUIRE(WavFileIO::Write(
190 outputPath, container.channelVectors, info.sampleRate));
191 }
192 }
193}

References AudioContainer::channelPointers, AudioContainer::channelVectors, and StretchingSequence::Create().

Here is the call graph for this function: