Skip to content

Commit 96e165a

Browse files
committed
Port new test to Catch2
1 parent d6057e2 commit 96e165a

File tree

1 file changed

+133
-0
lines changed

1 file changed

+133
-0
lines changed

tests/FrameMapper.cpp

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,139 @@ TEST_CASE( "redistribute_samples_per_frame", "[libopenshot][framemapper]" ) {
482482
r.Close();
483483
}
484484

485+
TEST_CASE( "Distribute samples", "[libopenshot][framemapper]" ) {
486+
// This test verifies that audio data can be redistributed correctly
487+
// between common and uncommon frame rates
488+
int sample_rate = 48000;
489+
int channels = 2;
490+
int num_seconds = 1;
491+
492+
// Source frame rates (varies the # of samples per frame)
493+
std::vector<openshot::Fraction> rates = {
494+
openshot::Fraction(30,1),
495+
openshot::Fraction(24,1) ,
496+
openshot::Fraction(119,4),
497+
openshot::Fraction(30000,1001)
498+
};
499+
500+
for (auto& frame_rate : rates) {
501+
// Init sin wave variables
502+
int OFFSET = 0;
503+
float AMPLITUDE = 0.75;
504+
int NUM_SAMPLES = 100;
505+
double angle = 0.0;
506+
507+
// Create cache object to hold test frames
508+
openshot::CacheMemory cache;
509+
510+
// Let's create some test frames
511+
for (int64_t frame_number = 1; frame_number <= (frame_rate.ToFloat() * num_seconds * 2); ++frame_number) {
512+
// Create blank frame (with specific frame #, samples, and channels)
513+
int sample_count = openshot::Frame::GetSamplesPerFrame(frame_number, frame_rate, sample_rate, channels);
514+
auto f = std::make_shared<openshot::Frame>(frame_number, sample_count, channels);
515+
f->SampleRate(sample_rate);
516+
517+
// Create test samples with sin wave (predictable values)
518+
float *audio_buffer = new float[sample_count * 2];
519+
for (int sample_number = 0; sample_number < sample_count; sample_number++) {
520+
// Calculate sin wave
521+
float sample_value = float(AMPLITUDE * sin(angle) + OFFSET);
522+
audio_buffer[sample_number] = abs(sample_value);
523+
angle += (2 * M_PI) / NUM_SAMPLES;
524+
}
525+
526+
// Add custom audio samples to Frame (bool replaceSamples, int destChannel, int destStartSample, const float* source,
527+
f->AddAudio(true, 0, 0, audio_buffer, sample_count, 1.0); // add channel 1
528+
f->AddAudio(true, 1, 0, audio_buffer, sample_count, 1.0); // add channel 2
529+
530+
// Add test frame to dummy reader
531+
cache.Add(f);
532+
533+
delete[] audio_buffer;
534+
}
535+
536+
openshot::DummyReader r(frame_rate, 1920, 1080, sample_rate, channels, 30.0, &cache);
537+
r.Open();
538+
539+
// Target frame rates
540+
std::vector<openshot::Fraction> mapped_rates = {
541+
openshot::Fraction(30,1),
542+
openshot::Fraction(24,1),
543+
openshot::Fraction(119,4),
544+
openshot::Fraction(30000,1001)
545+
};
546+
for (auto &mapped_rate : mapped_rates) {
547+
// Reset SIN wave
548+
angle = 0.0;
549+
550+
// Map to different fps
551+
FrameMapper map(&r, mapped_rate, PULLDOWN_NONE, sample_rate, channels, LAYOUT_STEREO);
552+
map.info.has_audio = true;
553+
map.Open();
554+
555+
// Loop through samples, and verify FrameMapper didn't mess up individual sample values
556+
int num_samples = 0;
557+
for (int frame_index = 1; frame_index <= (map.info.fps.ToInt() * num_seconds); frame_index++) {
558+
int sample_count = map.GetFrame(frame_index)->GetAudioSamplesCount();
559+
for (int sample_index = 0; sample_index < sample_count; sample_index++) {
560+
561+
// Calculate sin wave
562+
float predicted_value = abs(float(AMPLITUDE * sin(angle) + OFFSET));
563+
angle += (2 * M_PI) / NUM_SAMPLES;
564+
565+
// Verify each mapped sample value is correct (after being redistributed by the FrameMapper)
566+
float mapped_value = map.GetFrame(frame_index)->GetAudioSample(0, sample_index, 1.0);
567+
CHECK(predicted_value == Approx(mapped_value).margin(0.001));
568+
}
569+
// Increment sample value
570+
num_samples += map.GetFrame(frame_index)->GetAudioSamplesCount();
571+
}
572+
573+
float clip_position = 3.77;
574+
int starting_clip_frame = round(clip_position * map.info.fps.ToFloat()) + 1;
575+
576+
// Create Timeline (same specs as reader)
577+
Timeline t1(map.info.width, map.info.height, map.info.fps, map.info.sample_rate, map.info.channels,
578+
map.info.channel_layout);
579+
580+
Clip c1;
581+
c1.Reader(&map);
582+
c1.Layer(1);
583+
c1.Position(clip_position);
584+
c1.Start(0.0);
585+
c1.End(10.0);
586+
587+
// Add clips
588+
t1.AddClip(&c1);
589+
t1.Open();
590+
591+
// Reset SIN wave
592+
angle = 0.0;
593+
594+
for (int frame_index = starting_clip_frame; frame_index < (starting_clip_frame + (t1.info.fps.ToFloat() * num_seconds)); frame_index++) {
595+
for (int sample_index = 0; sample_index < t1.GetFrame(frame_index)->GetAudioSamplesCount(); sample_index++) {
596+
// Calculate sin wave
597+
float predicted_value = abs(float(AMPLITUDE * sin(angle) + OFFSET));
598+
angle += (2 * M_PI) / NUM_SAMPLES;
599+
600+
// Verify each mapped sample value is correct (after being redistributed by the FrameMapper)
601+
float timeline_value = t1.GetFrame(frame_index)->GetAudioSample(0, sample_index, 1.0);
602+
CHECK(predicted_value == Approx(timeline_value).margin(0.001));
603+
}
604+
}
605+
606+
// Close mapper
607+
map.Close();
608+
t1.Close();
609+
}
610+
611+
// Clean up reader
612+
r.Close();
613+
cache.Clear();
614+
615+
} // for rates
616+
}
617+
485618
TEST_CASE( "Json", "[libopenshot][framemapper]" )
486619
{
487620
DummyReader r(Fraction(30,1), 1280, 720, 48000, 2, 5.0);

0 commit comments

Comments
 (0)