Skip to content

Commit bdb161d

Browse files
committed
AudioWaveformData: Adding protection from divide by zero and readers with no audio, including additional unit tests and a faster zero() function
1 parent 4265d84 commit bdb161d

File tree

3 files changed

+84
-4
lines changed

3 files changed

+84
-4
lines changed

src/AudioWaveformer.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,20 @@ AudioWaveformData AudioWaveformer::ExtractSamples(int channel, int num_per_secon
4747
int total_samples = num_per_second * (reader->info.duration + 1.0);
4848
int extracted_index = 0;
4949

50+
// Force output to zero elements for non-audio readers
51+
if (!reader->info.has_audio) {
52+
total_samples = 0;
53+
}
54+
5055
// Resize and clear audio buffers
5156
data.resize(total_samples);
5257
data.zero(total_samples);
5358

59+
// Bail out, if no samples needed
60+
if (total_samples == 0 || reader->info.channels == 0) {
61+
return data;
62+
}
63+
5464
// Loop through all frames
5565
int sample_index = 0;
5666
float samples_max = 0.0;

src/AudioWaveformer.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,8 @@ namespace openshot {
3939

4040
/// Zero out # of values in both datasets
4141
void zero(int total_samples) {
42-
for (auto s = 0; s < total_samples; s++) {
43-
max_samples[s] = 0.0;
44-
rms_samples[s] = 0.0;
45-
}
42+
std::fill(max_samples.begin(), max_samples.end(), 0);
43+
std::fill(rms_samples.begin(), rms_samples.end(), 0);
4644
}
4745

4846
/// Scale # of values by some factor

tests/AudioWaveformer.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,75 @@ TEST_CASE( "Normalize & scale waveform data piano.wav", "[libopenshot][audiowave
130130
// Clean up
131131
r.Close();
132132
}
133+
134+
TEST_CASE( "Extract waveform from image (no audio)", "[libopenshot][audiowaveformer]" )
135+
{
136+
// Create a reader
137+
std::stringstream path;
138+
path << TEST_MEDIA_PATH << "front.png";
139+
FFmpegReader r(path.str());
140+
141+
// Create AudioWaveformer and extract a smaller "average" sample set of audio data
142+
AudioWaveformer waveformer(&r);
143+
AudioWaveformData waveform = waveformer.ExtractSamples(-1, 20, false);
144+
145+
CHECK(waveform.rms_samples.size() == 0);
146+
CHECK(waveform.max_samples.size() == 0);
147+
148+
// Clean up
149+
r.Close();
150+
}
151+
152+
TEST_CASE( "AudioWaveformData struct methods", "[libopenshot][audiowaveformer]" )
153+
{
154+
// Create a reader
155+
AudioWaveformData waveform;
156+
157+
// Resize data to 10 elements
158+
waveform.resize(10);
159+
CHECK(waveform.rms_samples.size() == 10);
160+
CHECK(waveform.max_samples.size() == 10);
161+
162+
// Set all values = 1.0
163+
for (auto s = 0; s < waveform.rms_samples.size(); s++) {
164+
waveform.rms_samples[s] = 1.0;
165+
waveform.max_samples[s] = 1.0;
166+
}
167+
CHECK(waveform.rms_samples[0] == Approx(1.0f).margin(0.00001));
168+
CHECK(waveform.rms_samples[9] == Approx(1.0f).margin(0.00001));
169+
CHECK(waveform.max_samples[0] == Approx(1.0f).margin(0.00001));
170+
CHECK(waveform.max_samples[9] == Approx(1.0f).margin(0.00001));
171+
172+
// Scale all values by 2
173+
waveform.scale(10, 2.0);
174+
CHECK(waveform.rms_samples.size() == 10);
175+
CHECK(waveform.max_samples.size() == 10);
176+
CHECK(waveform.rms_samples[0] == Approx(2.0f).margin(0.00001));
177+
CHECK(waveform.rms_samples[9] == Approx(2.0f).margin(0.00001));
178+
CHECK(waveform.max_samples[0] == Approx(2.0f).margin(0.00001));
179+
CHECK(waveform.max_samples[9] == Approx(2.0f).margin(0.00001));
180+
181+
// Zero out all values
182+
waveform.zero(10);
183+
CHECK(waveform.rms_samples.size() == 10);
184+
CHECK(waveform.max_samples.size() == 10);
185+
CHECK(waveform.rms_samples[0] == Approx(0.0f).margin(0.00001));
186+
CHECK(waveform.rms_samples[9] == Approx(0.0f).margin(0.00001));
187+
CHECK(waveform.max_samples[0] == Approx(0.0f).margin(0.00001));
188+
CHECK(waveform.max_samples[9] == Approx(0.0f).margin(0.00001));
189+
190+
// Access vectors and verify size
191+
std::vector<std::vector<float>> vectors = waveform.vectors();
192+
CHECK(vectors.size() == 2);
193+
CHECK(vectors[0].size() == 10);
194+
CHECK(vectors[0].size() == 10);
195+
196+
// Clear and verify internal data is empty
197+
waveform.clear();
198+
CHECK(waveform.rms_samples.size() == 0);
199+
CHECK(waveform.max_samples.size() == 0);
200+
vectors = waveform.vectors();
201+
CHECK(vectors.size() == 2);
202+
CHECK(vectors[0].size() == 0);
203+
CHECK(vectors[0].size() == 0);
204+
}

0 commit comments

Comments
 (0)